Kyle Simpson 的 OLOO 模式与原型设计模式

新手上路,请多包涵

Kyle Simpson 的“OLOO(对象链接到其他对象)模式”与原型设计模式有何不同?除了通过专门指示“链接”(原型的行为)的东西来创造它并澄清这里没有发生“复制”(类的行为)之外,他的模式到底介绍了什么?

这是 Kyle 在他的书中的模式示例,“你不知道 JS:this 和对象原型”:

 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."

原文由 shmuli 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 464
2 个回答

他的模式到底介绍了什么?

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

In both snippets, an x object is [[Prototype]] -linked to an object ( Bar.prototype or BarObj ), which in turn is linked to第三个对象( Foo.prototypeFooObj )。

片段之间的关系和委托是相同的。片段之间的内存使用情况是相同的。创建许多“子项”(又名,许多对象,如 x1x1000 等)在片段之间是相同的。委托的性能( x.yx.z )在片段之间是相同的。 OLOO 的对象创建性能 _较慢_,但 完整性检查 表明性能较慢确实不是问题。

我认为 OLOO 提供的是,仅表达对象并直接链接它们比通过构造函数/ new 机制间接链接它们要简单得多。后者假装是关于类的,但实际上只是表达委托的糟糕语法( 旁注: ES6 class 语法也是如此!)。

OLOO 只是去掉了中间人。

这是 class 与 OLOO 的 另一个比较

原文由 Kyle Simpson 发布,翻译遵循 CC BY-SA 3.0 许可协议

我读了 Kyle 的书,我发现它提供了很多信息,尤其是有关如何绑定 this 的详细信息。

优点:

对我来说,OLOO 有几个大优点:

1. 简单

OLOO 依靠 Object.create() 创建一个新对象 [[prototype]] 链接到另一个对象。您不必了解函数具有 prototype 属性,也不必担心其修改可能带来的任何潜在相关陷阱。

2. 更简洁的语法

这是有争议的,但我觉得 OLOO 语法(在许多情况下)比“标准”javascript 方法更简洁、更简洁,尤其是在涉及多态性时( super 样式调用)。

缺点:

我认为设计中有一点值得怀疑(实际上对上面的第 2 点有贡献),那就是与阴影有关:

在行为委托中,我们尽可能避免在 [[Prototype]] 链的不同级别命名相同的事物。

这背后的想法是对象有自己更具体的功能,然后在内部委托给链下游的功能。例如,您可能有一个 resource 对象,上面有一个 save() 函数,该函数将对象的 JSON 版本发送到服务器,但您也可能有一个 clientResource 具有 stripAndSave() 功能的对象,该功能首先删除不应发送到服务器的属性。

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

 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 会好很多,不过只是举个例子。)

原文由 Ed_ 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏