JavaScript中的原型继承惯例
-
03-07-2019 - |
题
我看到很多像这样的代码:
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;
还是不重要?
解决方案
'constructor'不会像它看起来那样做。除了非标准之外,这是避免使用它的一个很好的理由 - 坚持使用instanceof和prototype。
技术上:'构造函数'不是's'实例的属性,它是'Sub'原型对象的属性。当您在Mozilla中创建“Sub”函数时,您将获得一个新创建的默认Sub.prototype对象,该对象具有指向Sub函数的“构造函数”作为礼貌。
但是,然后用新的Base()替换该原型。返回Sub的原始默认原型丢失了;相反,Sub.prototype是Base的一个实例,没有任何重写的'constructor'属性。所以:
new Sub().constructor===
Sub.prototype.constructor===
new Base().constructor===
Base.prototype.constructor===
Base
......一直到最基本的对象,你的原型没有改变。
这样做是常规/更好吗?
在处理JavaScript对象/类时,没有一个约定;每个库的元类系统的行为略有不同。我还没有看到一个手动为每个派生类写“构造函数”的人,但是如果你真的想让真正的构造函数可用,它似乎是一个很好的解决方案。它还将使代码与不提供“构造函数”的浏览器/引擎兼容。
我会考虑给它一个不同的名称,以避免与现有的和不同行为的“构造函数”属性混淆。
其他提示
如果要测试对象是否恰好是Sub的实例,请使用 instanceof
运算符: -
print(s instanceof Sub);
如果你想知道对象是Sub的实例还是Sub的子类的实例,请使用 isPrototypeOf
方法: -
print(Sub.prototype.isPrototypeOf(s));
对,
Sub.prototype.constructor = Sub;
让你使用instanceof,但有一个更好的解决方案。看这里: GitHub上的TDD JS继承,找到寄生组合继承模式。代码是TDD,因此您应该能够非常快速地进行修改,然后只需更改名称即可开始使用。这基本上就是YAHOO.lang.extend所使用的(来源:雅虎员工和作者Nicholas Zakas的专业JavaScript for Web Developer's,2nd ED,第181页)。顺便说一句好书(不以任何方式附属!)
为什么呢?因为您正在使用的经典模式具有staticy引用变量(如果在基础对象中创建var arr = [1,2],则所有实例将具有读/写并且将“共享”'arr'的状态!你使用构造函数窃取你可以解决这个问题。看看我的例子。