凯尔-辛普森的OLO模式与原型设计模式的比较[英] Kyle Simpson's OLOO Pattern vs Prototype Design Pattern

本文是小编为大家收集整理的关于凯尔-辛普森的OLO模式与原型设计模式的比较的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

凯尔·辛普森(Kyle Simpson)的" oloo(链接到其他对象的对象)模式"是否与原型设计模式有所不同?除了通过专门指示"链接"(原型的行为)并澄清这里没有"复制"此处发生的"复制"(类的行为)之外,他的模式到底是什么?

这是凯尔(Kyle

var Foo = {
    init: function(who) {
        this.me = who;
    },
    identify: function() {
        return "I am " + this.me;
    }
};

var Bar = Object.create(Foo);

Bar.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."

推荐答案

他的模式到底是什么?

oloo包含原型链,而无需在其他(IMO令人困惑的)语义上分层以获得链接.

因此,这两个片段具有完全相同的结果,但要有不同的方式.

构造函数形式:

function Foo() {}
Foo.prototype.y = 11;

function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.z = 31;

var x = new Bar();
x.y + x.z;  // 42

oloo形式:

var FooObj = { y: 11 };

var BarObj = Object.create(FooObj);
BarObj.z = 31;

var x = Object.create(BarObj);
x.y + x.z;  // 42

在两个片段中,x对象[[Prototype]]链接到对象(Bar.prototype或BarObj),然后依次链接到第三对象(Foo.prototype或FooObj)./p>

摘要之间的关系和授权是相同的.摘要之间的内存使用情况相同.在摘要之间,创建许多"孩子"(又称x1到x1000等)的能力(例如x1> x1>)的能力是相同的.代表团的性能(x.y和x.z)在摘要之间是相同的. The object creation performance is slower with OLOO, but SANITY检查表明较慢的性能实际上不是问题.

我认为Oloo提供的是,仅表达对象并直接链接它们要比间接通过构造函数/new机制链接要简单得多.后者假装是关于课程的,但实际上只是表达授权的可怕语法(侧面注: es6 class语法!).

oloo只是削减了中间人.

这是 class vs oloo的另一个比较

其他推荐答案

我读了凯尔的书,我发现它确实有益,尤其是有关this的细节.

专利:

对我来说,有几个大专业人士:

1.简单

oloo依赖于Object.create()创建一个[[prototype]]链接到另一个对象的新对象.您不必了解功能具有prototype属性或担心其修改的任何潜在相关陷阱.

2.清洁器语法

这是可以有争议的,但是我觉得(在许多情况下)与"标准" JavaScript方法相比,Oloo语法更加整洁,更简洁,尤其是在多态性方面(super - 风格的呼叫).

>

cons:

我认为有一个可疑的设计(实际上有助于上面的第2点),这与阴影有关:

在行为委托中,我们避免在[[Prototype]]链的不同级别上命名相同的命名.

背后的想法是,对象具有自己的更具体的功能,然后在内部委派降低链条的功能.例如,您可能在其上有一个resource对象,其中包含save()函数,该函数将对象的JSON版本发送到服务器,但是您也可以具有具有clientResource对象,该对象具有stripAndSave()函数,首先删除不应发送到服务器的属性.

潜在的问题是:如果其他人出现并决定制作一个specialResource对象,而不完全了解整个原型链,他们可能会合理*决定为最后保存的时间戳保存,以保存在称为<<的属性下的最后保存C24>,它阴影resource对象上的基础save()功能两个链接在原型链上:

var resource = {
  save: function () { 
    console.log('Saving');
  }
};

var clientResource = Object.create(resource);

clientResource.stripAndSave = function () {
  // Do something else, then delegate
  console.log('Stripping unwanted properties');
  this.save();
};

var specialResource = Object.create( clientResource );

specialResource.timeStampedSave = function () {
  // Set the timestamp of the last save
  this.save = Date.now();
  this.stripAndSave();
};

a = Object.create(clientResource);
b = Object.create(specialResource);

a.stripAndSave();    // "Stripping unwanted properties" & "Saving".
b.timeStampedSave(); // Error!

这是一个特别人为的例子,但要点是,特别是不是阴影其他属性会导致某些尴尬的情况和大量使用词库!

也许可以更好地说明这是一种init方法 - 尤其是作为oolo避开构造函数函数的痛苦.由于每个相关的对象都可能需要这样的功能,因此适当地命名它们可能是一个乏味的练习,并且独特性可能使得很难记住要使用哪个.

*实际上不是特别合理(lastSaved会好多了,但这只是一个例子.)

其他推荐答案

"您不知道JS:此和对象原型"中的讨论和Oloo的介绍是令人发人深省的,我学到了很多文章. Oloo模式的优点在其他答案中很好地描述了;但是,我对此有以下宠物投诉(或缺少使我有效应用它的东西):

1

当" class""继承"另一个"类"中的经典模式中时,可以声明两个函数(" function声明"或"函数语句" ):

function Point(x,y) {
    this.x = x;
    this.y = y;
};

function Point3D(x,y,z) {
    Point.call(this, x,y);
    this.z = z;
};

Point3D.prototype = Object.create(Point.prototype);

相比之下,在Oloo模式中,用于定义基础和派生对象的不同句法形式:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    }
};


var Point3D = Object.create(Point);
Point3D.init = function(x,y,z) {
    Point.init.call(this, x, y);
    this.z = z;
};

您可以使用对象文字符号来定义基本对象的示例,而派生对象则不能使用相同的符号.这个不对称的使我陷入困境.

2

在Oloo模式中,创建一个对象是两个步骤:

  1. 呼叫Object.create
  2. 调用一些初始化对象的自定义,非标准方法(您必须记住的对象,因为它可能会因一个对象而变化到下一个对象):

     var p2a = Object.create(Point);
    
     p2a.init(1,1);
    

相反,在原型模式中,您使用标准操作员new:

var p2a = new Point(1,1);

3

在经典模式中,我可以创建"静态"实用程序函数,这些函数不会直接将其直接分配给"类"函数(而不是其.prototype)来直接应用于"即时".例如.喜欢函数square在以下代码中:

Point.square = function(x) {return x*x;};

Point.prototype.length = function() {
    return Math.sqrt(Point.square(this.x)+Point.square(this.y));
};

相比之下,在Oloo模式中,也可以在对象实例上使用任何"静态"函数(通过[[[Prototype]]链):

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    },
    square: function(x) {return x*x;},
    length: function() {return Math.sqrt(Point.square(this.x)+Point.square(this.y));}
};

本文地址:https://www.itbaoku.cn/post/627575.html

问题描述

Does Kyle Simpson's "OLOO (Objects Linking to Other Objects) Pattern" differ in any way from the the Prototype design pattern? Other than coining it by something that specifically indicates "linking" (the behavior of prototypes) and clarifying that there's no to "copying" happening here (a behavior of classes), what exactly does his pattern introduce?

Here's an example of Kyle's pattern from his book, "You Don't Know JS: this & Object Prototypes":

var Foo = {
    init: function(who) {
        this.me = who;
    },
    identify: function() {
        return "I am " + this.me;
    }
};

var Bar = Object.create(Foo);

Bar.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."

推荐答案

what exactly does his pattern introduce?

OLOO embraces the prototype chain as-is, without needing to layer on other (IMO confusing) semantics to get the linkage.

So, these two snippets have the EXACT same outcome, but get there differently.

Constructor Form:

function Foo() {}
Foo.prototype.y = 11;

function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.z = 31;

var x = new Bar();
x.y + x.z;  // 42

OLOO Form:

var FooObj = { y: 11 };

var BarObj = Object.create(FooObj);
BarObj.z = 31;

var x = Object.create(BarObj);
x.y + x.z;  // 42

In both snippets, an x object is [[Prototype]]-linked to an object (Bar.prototype or BarObj), which in turn is linked to third object (Foo.prototype or FooObj).

The relationships and delegation are identical between the snippets. The memory usage is identical between the snippets. The ability to create many "children" (aka, many objects like x1 through x1000, etc) is identical between the snippets. The performance of the delegation (x.y and x.z) is identical between the snippets. The object creation performance is slower with OLOO, but sanity checking that reveals that the slower performance is really not an issue.

What I argue OLOO offers is that it's much simpler to just express the objects and directly link them, than to indirectly link them through the constructor/new mechanisms. The latter pretends to be about classes but really is just a terrible syntax for expressing delegation (side note: so is ES6 class syntax!).

OLOO is just cutting out the middle-man.

Here's another comparison of class vs OLOO.

其他推荐答案

I read Kyle's book, and I found it really informative, particularly the detail about how this is bound.

Pros:

For me, there a couple of big pros of OLOO:

1. Simplicity

OLOO relies on Object.create() to create a new object which is [[prototype]]-linked to another object. You don't have to understand that functions have a prototype property or worry about any of the potential related pitfalls that come from its modification.

2. Cleaner syntax

This is arguable, but I feel the OLOO syntax is (in many cases) neater and more concise than the 'standard' javascript approach, particularly when it comes to polymorphism (super-style calls).

Cons:

I think there is one questionable bit of design (one that actually contributes to point 2 above), and that is to do with shadowing:

In behaviour delegation, we avoid if at all possible naming things the same at different levels of the [[Prototype]] chain.

The idea behind this is that objects have their own more specific functions which then internally delegate to functions lower down the chain. For example, you might have a resource object with a save() function on it which sends a JSON version of the object to the server, but you may also have a clientResource object which has a stripAndSave() function, which first removes properties that shouldn't be sent to the server.

The potential problem is: if someone else comes along and decides to make a specialResource object, not fully aware of the whole prototype chain, they might reasonably* decide to save a timestamp for the last save under a property called save, which shadows the base save() functionality on the resource object two links down the prototype chain:

var resource = {
  save: function () { 
    console.log('Saving');
  }
};

var clientResource = Object.create(resource);

clientResource.stripAndSave = function () {
  // Do something else, then delegate
  console.log('Stripping unwanted properties');
  this.save();
};

var specialResource = Object.create( clientResource );

specialResource.timeStampedSave = function () {
  // Set the timestamp of the last save
  this.save = Date.now();
  this.stripAndSave();
};

a = Object.create(clientResource);
b = Object.create(specialResource);

a.stripAndSave();    // "Stripping unwanted properties" & "Saving".
b.timeStampedSave(); // Error!

This is a particularly contrived example, but the point is that specifically not shadowing other properties can lead to some awkward situations and heavy use of a thesaurus!

Perhaps a better illustration of this would be an init method - particularly poignant as OOLO sidesteps constructor type functions. Since every related object will likely need such a function, it may be a tedious exercise to name them appropriately, and the uniqueness may make it difficult to remember which to use.

*Actually it's not particularly reasonable (lastSaved would be much better, but it's just an example.)

其他推荐答案

The discussion in "You Don't Know JS: this & Object Prototypes" and the presentation of the OLOO is thought-provoking and I have learned a ton going through the book. The merits of the OLOO pattern are well-described in the other answers; however, I have the following pet complaints with it (or am missing something that prevents me from applying it effectively):

1

When a "class" "inherits" another "class" in the classical pattern, the two function can be declared similar syntax ("function declaration" or "function statement"):

function Point(x,y) {
    this.x = x;
    this.y = y;
};

function Point3D(x,y,z) {
    Point.call(this, x,y);
    this.z = z;
};

Point3D.prototype = Object.create(Point.prototype);

In contrast, in the OLOO pattern, different syntactical forms used to define the base and the derived objects:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    }
};


var Point3D = Object.create(Point);
Point3D.init = function(x,y,z) {
    Point.init.call(this, x, y);
    this.z = z;
};

As you can see in the example above the base object can be defined using object literal notation, whereas the same notation can't be used for the derived object. This asymmetry bugs me.

2

In the OLOO pattern, creating an object is two steps:

  1. call Object.create
  2. call some custom, non standard method to initialize the object (which you have to remember since it may vary from one object to the next):

     var p2a = Object.create(Point);
    
     p2a.init(1,1);
    

In contrast, in the Prototype pattern you use the standard operator new:

var p2a = new Point(1,1);

3

In the classical pattern I can create "static" utility functions that don't apply directly to an "instant" by assigning them directly to the "class" function (as opposed to its .prototype). E.g. like function square in the below code:

Point.square = function(x) {return x*x;};

Point.prototype.length = function() {
    return Math.sqrt(Point.square(this.x)+Point.square(this.y));
};

In contrast, in the OLOO pattern any "static" functions are available (via the [[prototype]] chain) on the object instances too:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    },
    square: function(x) {return x*x;},
    length: function() {return Math.sqrt(Point.square(this.x)+Point.square(this.y));}
};