当前位置: 首页 > 知识库问答 >
问题:

凯尔·辛普森的OLOO模式与原型设计模式

阎乐池
2023-03-14

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

这是凯尔的模式的一个例子,来自他的书《你不知道JS:这个》

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

共有3个答案

贾成天
2023-03-14

“你不知道JS:这个”中的讨论

1

当一个“类”在经典模式中“继承”另一个“类”时,两个函数可以用类似的语法声明(“函数声明”或“函数语句”):

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模式中,创建对象有两个步骤:

>

  • call<code>对象。创建
  • 调用一些自定义的非标准方法来初始化对象(您必须记住这一点,因为它可能因对象而异):

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

    相反,在原型模式中,您使用标准操作符< code>new:

    var p2a = new Point(1,1);
    

    3.

    在经典模式中,我可以通过将“静态”效用函数直接分配给“类”函数(与其<代码>相反),来创建不直接应用于“即时”的“静态”效用函数。原型)。例如,类似于下面代码中的函数< code>square:

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

    相反,在OLOO模式中,对象实例上也可以使用任何“静态”函数(通过[[原型]]链):

    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));}
    };
    

  • 洪育
    2023-03-14

    我读了凯尔的书,我发现它非常有信息,尤其是关于这个是如何绑定的细节。

    对我来说,OLOO有两大优点:

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

    这是有争议的,但我觉得OLOO语法(在许多情况下)比“标准”javascript方法更简洁,尤其是在多态(超级风格的调用)方面。

    我认为设计中有一点值得怀疑(实际上有助于上述第2点),那就是阴影:

    在行为委托中,我们尽可能避免在< code>[[Prototype]]链的不同层次上对事物进行相同的命名。

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

    潜在的问题是:如果其他人出现并决定制作一个特殊的资源对象,而不完全了解整个原型链,他们可能会合理地*决定在名为 save 的属性下保存最后一次保存的时间戳,该属性在原型链的两个链接下隐藏了资源对象上的基本 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!
    

    这是一个特别人为的例子,但关键是,特别是不遮蔽其他属性会导致一些尴尬的情况和大量使用同义词库!

    也许一个更好的例子是<code>init</code>方法——特别是当OOLO绕过构造函数类型函数时。由于每个相关对象都可能需要这样一个函数,因此适当地命名它们可能是一项繁琐的工作,而唯一性可能会让人难以记住要使用哪一个。

    *实际上它不是特别合理(lastSaved会更好,但这只是一个例子。)

    呼延曜灿
    2023-03-14

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

    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
    

    在这两个代码段中,< code>x对象链接到一个对象(< code>Bar.prototype或< code>BarObj),该对象又链接到第三个对象(< code>Foo.prototype或< code>FooObj)。

    代码段之间的关系和委派是相同的。代码段之间的内存使用情况相同。创建许多“子对象”(即许多对象,如 x1x1000 等)的能力在代码片段之间是相同的。代码段之间的委派(x.yx.z)的性能相同。使用 OLOO 的对象创建性能较慢,但健全性检查显示性能较慢实际上不是问题。

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

    OLOO只是避开了中间人。

    这是class与OLOO的另一个比较。

     类似资料:
    • 6. 原型模式(Prototype) Intent 使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。 Class Diagram Implementation // java public abstract class Prototype { abstract Prototype myClone(); } // java public class ConcreteProt

    • 介绍 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。 正文 对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是创建的一个对象作为另外一个对象的prototype属性值。原型对象本身就是有效地利用了每个构造器创建的对象,例如,如果一个构造函数的原型包含了一个name属性(见后面的例子),那通过这个构造函数创建的

    • 主要内容:1.GRASP:通用职责分配软件模式(共9种),2.SOLID:设计原则(共5种),3.GOF:设计模式(共23种),4.其他必要设计原则GRASP: 通用职责分配软件模式(共9种) SOLID:设计原则(共5种) GOF:设计模式(共23种) 其他必要设计原则 1.GRASP:通用职责分配软件模式(共9种) 告诉我们怎样设计问题空间中的类与分配它们的行为职责,以及明确类之间的相互关系等 Infomation Expert(信息专家) Creator(创造者) Low coupling

    • 本文向大家介绍Java设计模式之Prototype原型模式,包括了Java设计模式之Prototype原型模式的使用技巧和注意事项,需要的朋友参考一下 一、场景描述 创建型模式中,从工厂方法模式,抽象工厂模式,到建造者模式,再到原型模式,我的理解是,创建对象的方式逐步从编码实现转向内存对象处理。 例如,在“仪器数据采集器”的子类/对象“PDF文件数据采集器”和“Excel文件数据采集器”的创建过程

    • 本文向大家介绍JavaScript设计模式之原型模式分析【ES5与ES6】,包括了JavaScript设计模式之原型模式分析【ES5与ES6】的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JavaScript设计模式之原型模式。分享给大家供大家参考,具体如下: 从设计模式的角度讲,原型模式是用于创建对象的一种模式,若需要创建一个对象,一种方法是先指定其类型,然后通过类来创建这个对象,另一

    • 本文向大家介绍JavaScript设计模式之原型模式(Object.create与prototype)介绍,包括了JavaScript设计模式之原型模式(Object.create与prototype)介绍的使用技巧和注意事项,需要的朋友参考一下 原型模式说明 说明:使用原型实例来 拷贝 创建新的可定制的对象;新建的对象,不需要知道原对象创建的具体过程; 过程:Prototype => new P