JavaScript中的原型继承规范

7

我看到很多这样的代码:

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。 - GR1000
许多框架会调整constructor属性,以正确指向子类的构造函数。我在上面展示的代码中有一篇文章涉及到这个问题和其他问题。http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html - Ruan Mendes
3个回答

9
“constructor”并不像它看起来的那样工作。除了它的非标准性外,这是避免使用它的一个很好的理由 - 坚持使用instanceof和prototype。
技术上来说,“constructor”不是“s”实例的属性,而是“Sub”原型对象的属性。在Mozilla中创建“Sub”函数时,您会得到一个新的默认Sub.prototype对象,其中有一个指向Sub函数的“constructor”属性。
但是,您随后用一个新的Base()替换了该原型。原始的默认原型与指向Sub的链接丢失了;相反,Sub.prototype是一个没有覆盖“constructor”属性的Base实例。所以:
new Sub().constructor===
Sub.prototype.constructor===
new Base().constructor===
Base.prototype.constructor===
Base

……一直到最基本的对象,而其原型没有改变。

这是常规/更好的做法吗?

在处理 JavaScript 对象/类时,并不存在一个共同的约定;每个库的元类系统行为略有不同。我没有看到过任何手动将“constructor”写入每个派生类的,但如果你真的想要具有真正的构造函数可用,那么它似乎是任何一个解决方案都可以的,它还会使代码与浏览器/引擎兼容,这些浏览器/引擎不提供“constructor”。

不过,我会考虑给它一个不同的名称,以避免与现有且行为不同的“constructor”属性混淆。


3

如果你想测试一个对象是否确切地是 Sub 的实例,请使用 instanceof 运算符:

print(s instanceof Sub);

如果您想知道一个对象是Sub的实例还是Sub子类的实例,请使用isPrototypeOf方法:

print(Sub.prototype.isPrototypeOf(s));

1

是的,

Sub.prototype.constructor = Sub;

让你使用instanceof,但有更好的解决方案。看这里:TDD JS Inheritance on GitHub,找到寄生组合继承模式。代码是TDD'd,所以你应该能够很快地理解它,然后只需更改名称即可开始。这基本上就是YAHOO.lang.extend使用的内容(来源:雅虎员工和作者Nicholas Zakas的《Web开发人员的专业JavaScript,第2版,第181页》)。顺便说一句,这是一本不错的书(与任何方式无关!)

为什么?因为你正在使用的经典模式具有静态引用变量(如果在基本对象中创建var arr = [1,2],所有实例都将具有读/写权限,并且将“共享”'arr'的状态!如果您使用构造函数窃取,可以解决此问题。请参阅我的示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接