【问题标题】:Confusion about setting something.prototype.__proto__关于设置 something.prototype.__proto__ 的困惑
【发布时间】:2011-07-20 21:18:12
【问题描述】:

在 Node.js 的 Express 模块的代码中,我遇到了这一行,为服务器设置继承:

Server.prototype.__proto__ = connect.HTTPServer.prototype;

我不确定这是做什么的 - MDC 文档 (https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited#prototype_and_proto) 似乎说我可以做吧:

Server.prototype = connect.HTTPServer.prototype;

确实,我做了这个测试:

var parent = function(){}
parent.prototype = {
    test: function(){console.log('test')};
}

var child1 = function(){};
child1.prototype = parent.prototype;
var instance1 = new child1();
instance1.test();     // 'test'

var child2 = function(){};
child2.prototype.__proto__ = parent.prototype;
var instance2 = new child2();
instance2.test();     // 'test'

看起来是一样的?所以是的,我想知道设置 object.prototype.__proto 的目的是什么。谢谢!

【问题讨论】:

标签: javascript node.js


【解决方案1】:

查看this page (mckoss.com) 上的图表,该图表显示了小层次结构的prototypeconstructor__proto__ 关系。图表下方的代码也很好地描述了这种关系。

当你有一个函数Base,并设置定义的函数对象的原型时,语句Derived.prototype = new Base;Derived.prototype__proto__(实际上是内部[[prototype]])自动设置为Base.prototype,使 Derived 本身成为一个可以实例化对象的类。这似乎是一种更符合标准的定义派生类的方式。

根据我的阅读,__proto__ 是一种访问对象内部[[prototype]] 的非标准方式。它似乎得到了很好的支持,但我不确定它是否应该被信任。

无论如何,您的示例Server.prototype.__proto__ = connect.HTTPServer.prototype; 似乎以相反的方式进行推导:首先定义一个对象,Server 通过定义构造函数和原型,然后手动连接内部[[prototype]] 以进行变形将其转换为从HTTPServer 派生的类。

至于您建议的替代方案,Server.prototype = connect.HTTPServer.prototype;:这是个坏主意。在这里,您将Server 的原型设置为与HTTPServer 的原型相同的对象。因此,您对Server 类所做的任何更改都将直接反映在HTTPServer 中,并且可以从HTTPServer 的其他派生类访问。如果派生自HTTPServer 的两个类尝试定义同一个成员,您可以想象一下混乱。

【讨论】:

  • 感谢 mckoss 文章链接 - 在我们结束之前,只需澄清一个问题,我认为我的观点是正确的:如果没有人使用原型,我建议的替代方案 (Derived.prototype = Base.prototype) 很好,我们之所以要做“Derived.prototype = new Base”(这会将 Derived 的原型设置为一个新对象,其 [[prototype]] 设置为 Base.prototype),是为了确保任何对 Derived 原型的修改不能影响 Base 的原型。
  • 你的理解和我的一样。由于我对 Javascript 不是很精通,但可能还有一些其他的细微之处我错过了。另外,如果您需要实例化派生类,Derived.prototype.constructor 将是Base.prototype.constructor,因此如果您使用new Derived,它将调用错误的函数。我想。
【解决方案2】:

非标准属性__proto__ 允许您设置现有对象的原型。

在你的例子中,两个版本都会达到同样的效果,但是有区别:

child1的原型与parent的原型相同,而child2的原型是一个空对象,而这个空对象的原型与parent的原型相同。

当然child2和它的原型没有test方法,这个方法会在原型链中往上查找。

还要考虑这个:

您只想创建一个应该从另一个对象继承的对象。现在,您可以编写一个构造函数,但是 JavaScript 有对象字面量表示法可以直接创建对象,并且您想使用它。

如果您有构造函数,让新对象从另一个对象继承就像将构造函数的prototype 设置为该对象一样简单。

显然这不适用于对象字面量。但是在 Firefox 中你可以使用__proto__ 来设置它:

var server = {
    __proto__: connect.HTTPServer.prototype,
    other: properties
};

由于这个属性不是标准的,你应该避免使用它。

【讨论】:

  • 谢谢菲利克斯,你的 + Dysaster 的答案结合起来真的很清楚,希望我能标记他们两个
  • 实际上,proto 是 ECMAScript 6 标准,它在现代浏览器 (IE9+) 中也得到了很好的支持
猜你喜欢
  • 2012-09-28
  • 1970-01-01
  • 2019-09-13
  • 2022-11-26
  • 2019-05-17
  • 2020-03-06
  • 2016-03-16
  • 2013-07-27
  • 1970-01-01
相关资源
最近更新 更多