JavaScript 中原型继承的约定
Posted
技术标签:
【中文标题】JavaScript 中原型继承的约定【英文标题】:Convention for prototype inheritance in JavaScript 【发布时间】:2010-09-28 23:42:32 【问题描述】:我看到很多这样的代码:
function Base()
function Sub()
Sub.prototype = new Base();
但是,如果你这样做:
s = new Sub();
print(s.constructor == Sub);
这是错误的。这似乎让我感到困惑,因为 s 的构造函数确实是 Sub。这样做是否传统/更好?
function Base()
function Sub()
Sub.prototype = new Base();
Sub.prototype.constructor = Sub;
还是真的不重要?
【问题讨论】:
我刚刚通过一个 html 页面作为 alert(s.constructor == Sub) 运行比较,它返回 true。 许多框架调整constructor
属性以正确指向子类的构造函数。我有帖子处理上面显示的代码中的这个问题和其他问题。 js-bits.blogspot.com/2010/08/…
【参考方案1】:
如果你想测试一个对象是否完全是 Sub 的一个实例,请使用instanceof
操作符:-
print(s instanceof Sub);
如果您想知道一个对象是 Sub 的实例还是 Sub 的子类的实例,请使用 isPrototypeOf
方法:-
print(Sub.prototype.isPrototypeOf(s));
【讨论】:
【参考方案2】:'constructor' 不像它看起来那样做。除了它的非标准性之外,这也是避免使用它的一个很好的理由 - 坚持使用 instanceof 和原型。
从技术上讲:“构造函数”不是“s”实例的属性,它是“子”原型对象的属性。当您在 Mozilla 中创建“Sub”函数时,您会得到一个新创建的默认 Sub.prototype 对象,它有一个“构造函数”指向 Sub 函数。
但是,您随后用新的 Base() 替换该原型。带有返回 Sub 的链接的原始默认原型丢失;相反,Sub.prototype 是 Base 的一个实例,没有任何覆盖的“构造函数”属性。所以:
new Sub().constructor===
Sub.prototype.constructor===
new Base().constructor===
Base.prototype.constructor===
Base
...一直到您没有更改其原型的最基本对象。
这样做是否传统/更好?
在处理 javascript 对象/类时,没有一个约定;每个库的元类系统的行为都略有不同。我还没有看到手动将“构造函数”写入每个派生类,但如果您真的想要真正的构造函数可用,它似乎是一个很好的解决方案;它还将使代码与不提供“构造函数”的浏览器/引擎兼容。
不过,我会考虑给它一个不同的名称,以避免与现有且行为不同的“构造函数”属性混淆。
【讨论】:
【参考方案3】:是的,
Sub.prototype.constructor = Sub;
让我们使用 instanceof,但有更好的解决方案。看这里:,TDD JS Inheritance on GitHub,找到寄生组合继承模式。该代码是 TDD 的,因此您应该能够非常快速地了解它,然后只需更改名称即可开始。这基本上是 YAHOO.lang.extend 使用的(来源:yahoo 员工和作者 Nicholas Zakas 的 Professional JavaScript for Web Developer's,第 2 版,第 181 页)。顺便说一句,好书(不以任何方式附属!)
为什么?因为您正在使用的经典模式具有静态引用变量(如果您在基础对象中创建 var arr = [1,2],则所有实例都将具有读/写功能并且将“共享状态”的“arr”!如果您使用构造函数窃取你可以解决这个问题。请参阅我的示例。
【讨论】:
以上是关于JavaScript 中原型继承的约定的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript高级原型和继承相关:原型对象函数原型原型链和继承继承的优化对象判断相关方法