Kyle Simpson的“OLOO(链接到其他对象的对象)模式”与原型设计模式有何不同?除了通过专门指示“链接”(原型的行为)的东西创造它并澄清这里没有“复制”(类的行为),他的模式究竟引入了什么?
这是他的书"You Don't Know JS: this & Object Prototypes"中的an example of Kyle's pattern:
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."
8 回答
OLOO按原样包含原型链,无需在其他(IMO混淆)语义上进行分层以获得链接 .
因此,这两个片段具有完全相同的结果,但以不同方式实现 .
Constructor Form:
OLOO Form:
在两个片段中,
x
对象都链接到一个对象(Bar.prototype
或BarObj
),该对象又链接到第三个对象(Foo.prototype
或FooObj
) .片段之间的关系和委托是相同的 . 片段之间的内存使用情况相同 . 在片段之间创建许多"children"(也就是诸如
x1
到x1000
之类的许多对象)的能力是相同的 . 代理的性能(x.y
和x.z
)在代码段之间是相同的 . OLOO的对象创建性能较慢,但sanity checking that表明性能较慢并不是问题 .我认为OLOO提供的是,只表达对象并直接链接它们比通过构造函数/
new
机制间接链接它们要简单得多 . 后者假装是关于类,但实际上只是表达委派的一种可怕的语法( side note: 所以是ES6class
语法!) .OLOO is just cutting out the middle-man.
这是
class
与OLOO的another comparison .我读了凯尔的书,我发现它确实很有用,特别是关于
this
如何绑定的细节 .优点:
对我来说,有两个OLOO的大职业选手:
1.简洁
OLOO依赖
Object.create()
创建一个新对象,该对象与另一个对象链接 . 您不必了解函数具有prototype
属性或担心其修改带来的任何潜在相关缺陷 .2.更清晰的语法
这是有争议的,但我觉得OLOO语法(在很多情况下)比'standard'javascript方法更整洁,更简洁,特别是在涉及多态(
super
-样式调用)时 .缺点:
我认为有一个有问题的设计(实际上有助于上面的第2点),这与阴影有关:
这背后的想法是对象有自己更具体的功能,然后内部委托给链下游的功能 . 例如,您可能有一个带有
save()
函数的resource
对象将该对象的JSON版本发送到服务器,但您可能还有一个clientResource
对象具有stripAndSave()
函数,该函数首先删除不应该的属性 . 发送到服务器 .潜在的问题是:如果其他人出现并决定制作一个
specialResource
对象,而不是完全了解整个原型链,他们可能会合理地*决定在名为save
的属性下保存最后一次保存的时间戳,这会影响基础在resource
对象上的save()
功能在原型链上有两个链接:这是一个特别人为的例子,但重点是,特别是不遮蔽其他属性可能会导致一些尴尬的情况和大量使用同义词库!
也许更好地说明这个方法是一个
init
方法 - 尤其令人痛苦,因为OOLO会回避构造函数类型的功能 . 由于每个相关对象都可能需要这样的功能,因此对它们进行适当命名可能是一项繁琐的工作,并且唯一性可能使得难以记住使用哪个 .*实际上它并不是特别合理(lastSaved会好得多,但它只是一个例子 . )
“你不了解JS:这个和对象原型”中的讨论以及OLOO的演示是发人深省的,我已经学到了很多东西 . OLOO模式的优点在其他答案中有详细描述;但是,我有以下宠物对它的投诉(或遗漏了一些阻止我有效应用它的东西):
1
当一个经典模式中的另一个"inherits"时,这两个函数可以声明类似的语法("function declaration" or "function statement"):
相反,在OLOO模式中,用于定义基础和派生对象的不同语法形式:
正如您在上面的示例中所看到的,基础对象可以使用对象文字表示法定义,而相同的表示法不能用于派生对象 . 这种不对称性让我感到困惑 .
2
在OLOO模式中,创建对象有两个步骤:
来电
Object.create
调用一些自定义的非标准方法来初始化对象(您必须记住它,因为它可能因对象而异):
相反,在Prototype模式中,您使用标准运算符
new
:3
在经典模式中,我可以通过将它们直接分配给"class"函数(而不是
.prototype
)来创建"static"实用函数,这些函数不直接应用于"instant" . 例如 . 像下面代码中的函数square
:相反,在OLOO模式中,对象实例上的任何“静态”函数也可用(通过[[prototype]]链):
正如Kyle解释当两个对象被链接时,它们不能通过
[[Prototype]]
链接将一个对象链接到另一个对象,您可以随时更改它 . If you take two [[Prototype]] linked objects created through OLOO style as being dependent on each other, you should also think the same about the ones created through constructor calls.现在考虑一下,你认为
foo
bar
和baz
依赖于彼此吗?现在让我们做同样的
constructor
样式代码 -b / w后者与前一代码的唯一区别在于,后者通过
constructor
函数(Foo.prototype
,Bar.prototype
,Baz.prototype
)的任意对象将foo
,bar
,baz
对象相互链接,但在前者中(OLOO
style)它们是直接链接的 . 这两种方式只是将foo
,bar
,baz
彼此直接连接,直接连接到前者,间接链接到后者 . 但是,在这两种情况下,对象都是彼此独立的,因为它不能从其他类继承 . 您始终可以更改对象应该委派的对象 .所以他们都是彼此独立的 .
是的,这确实可能 -
让我们使用
Tech
作为实用对象 -创建尽可能多的对象链接到
Tech
-你认为
html
,css
,js
对象是否相互连接?不,他们不知道我们如何用constructor
功能做到这一点 -创建尽可能多的对象链接到
Tech.proptotype
-一些检查(避免console.log) -
您如何看待这些
constructor
-对象(html
,css
,js
)对象与OLOO
样式代码有何不同?事实上,它们服务于同一目的 . 在OLOO
-style中,一个对象委托给Tech
(委托是显式设置的),而在constructor
-style中,一个对象委托给Tech.prototype
(委托是隐式设置的) . 最终,您最终将三个对象(彼此之间没有链接)链接到一个对象,直接使用OLOO
-style,间接使用constructor
-style .不,
ObjB
这里不是任何类ObjA
的实例(在经典语言中) . It sould be said like objB object is made delegate to ObjA object at it's creation time" . 如果您使用了构造函数,那么您可以使用.prototype
进行相同的'coupling' .@Marcus @bholben
也许我们可以做这样的事情 .
当然,创建一个链接到Point2D对象原型的Point3D对象有点愚蠢,但这不是重点(我希望与你的例子保持一致) . 无论如何,就投诉而言:
__proto__ = ...
更加皱眉 . 我们现在也可以在常规对象上使用super,如Point3D.init()
中所示 . 另一种方法是做类似的事情虽然我不是特别喜欢语法 .
p = Object.create(Point)
然后p.init()
包装到构造函数中 . 例如Point.create(x,y)
. 使用上面的代码,我们可以按以下方式创建Point3D
"instance" .Point.create()
方法静态 .或者,使用ES6 Symbols,您可以安全地扩展Javascript基类 . 因此,您可以保存自己的一些代码并在Object.prototype上定义特殊属性 . 例如,
@james emanon - 所以,你指的是多重继承(在“你不了解JS:这个和对象原型”一书中的第75页讨论过) . 我们可以在下划线的“扩展”功能中找到该机制 . 您在示例中说明的对象名称有点混合苹果,橙子和糖果,但我理解背后的观点 . 根据我的经验,这将是OOLO版本:
这是一个简单的例子,但显示的是我们只是将对象链接在相当平坦的结构/形式中,并且仍然可以使用来自多个对象的方法和属性 . 我们实现与类/“复制属性”方法相同的事物 . Kyle总结(第114页,“this&Object Prototypes”):
我知道更自然的方式是在一个地方/函数调用中声明所有“父”(仔细:))对象,而不是建模整个链 .
它需要的是根据这一点在我们的应用程序中改变思维和建模问题 . 我也习惯了 . 希望它有所帮助,凯尔本人的最终判决将是伟大的 . :)
@Marcus,就像你一样,我一直热衷于OLOO,也不喜欢你的第一点所描述的不对称性 . 我一直在玩抽象,以恢复对称性 . 您可以创建一个
link()
函数来代替Object.create()
. 使用时,您的代码看起来像这样......请记住
Object.create()
有第二个可以传入的参数 . 这是利用第二个参数的链接函数 . 它还允许一些自定义配置......当然,我认为@Kyle不支持在Point3D对象中隐藏
init()
函数 . ;-)有没有办法让OLOO超过“两个”对象..所有的例子我都是基于基础的例子(参见OP的例子) . 假设我们有以下对象,我们如何创建一个具有“其他”三个属性的“第四”对象?翼...
这些对象是任意的,可以包含各种行为 . 但要点是,我们有'n'个对象,而我们的新对象需要三个方面的东西 .
而不是给定的例子ala:
但是,我们的newObject =(按钮,自行车,鞋子)......
在OLOO中实现这一目标的模式是什么?