问题 关于设置something.prototype .__ proto__的困惑


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

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

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

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是为了什么。谢谢!


4195
2018-03-22 22:10


起源

可能重复 __proto__ VS. JavaScript中的原型 - Krzysztof Safjanowski


答案:


看看图表 这一页 (mckoss.com)显示了 prototypeconstructor__proto__ 小层次的关系。此外,图下方的代码也很好地描述了这种关系。

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

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

无论如何,你的例子 Server.prototype.__proto__ = connect.HTTPServer.prototype; 似乎以相反的方式进行推导:首先定义一个对象, Server 通过定义构造函数和proto,然后挂钩内部 [[prototype]] 手动将其变形为派生自的类 HTTPServer

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


10
2018-03-22 22:39



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


非标准的财产 __proto__ 让你设置一个原型 现有 目的。

在您的示例中,两个版本都将达到相同的效果,但存在差异:

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

当然是 child2 它的原型没有方法 test,这个方法将在原型链中进一步查找。

还要考虑这个:

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

如果你有一个构造函数,让新对象继承另一个对象就像设置一样容易 prototype 该对象的构造函数。

显然这对于​​对象文字不起作用。但在Firefox中你可以使用 __proto__设置它:

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

由于此属性不是标准属性,因此应避免使用它。


2
2018-03-22 22:28



谢谢菲利克斯,你的+ Dysaster的答案结合了真正澄清的事情,希望我能够标记它们 - ambertch
其实, 原 在ECMAScript 6标准中,它在现代浏览器中也得到了很好的支持(IE9 +) - csuwldcat