在您的示例中,Box 构造函数仅在您设置 NewBox.prototype 对象时才会执行。
您可以通过使用Function.prototype.apply 方法调用NewBox 内的Box 构造函数来解决此问题,以设置this 值并转发所有参数值,例如:
//..
var NewBox = function() {
Box.apply(this, arguments);
this.newThing = true;
};
//..
var a = new NewBox();
var b = new NewBox();
// assuming your `generateUniqueId` function
// increments a number
alert(a.id); // will alert 1
alert(b.id); // will alert 2
现在,每次调用NewBox 构造函数来创建一个新的对象实例(new NewBox();),它都会调用Box 函数来应用它的所有逻辑。这将帮助您避免一遍又一遍地重复父构造函数的逻辑。
apply 用于调用“父”构造函数,将 this 值设置为由 NewBox 构造函数创建的对象实例,我们将提供的所有参数传递给该函数。
您的示例还显示了一个常见问题,当您通过NewBox.prototype = new Box(); 表达继承关系时,Box 构造函数被调用并且它具有副作用,这个新对象将被初始化并且您的generateUniqueId 函数将被执行为第一次,如果你想避免这种情况,你需要使用临时构造函数,只是为了创建一个继承自 Box.prototype 的新对象,或者出于相同目的使用新的 ECMAScript 5 Object.create 方法,例如:
function inherit(o) {
function Tmp() {}
Tmp.prototype = o;
return new Tmp();
}
//.....
NewBox.prototype = inherit(Box.prototype);
或者:
NewBox.prototype = Object.create(Box.prototype);
这样,您无需第一次运行 Box 构造函数即可表达相同的继承层次结构,从而避免了它可能导致的任何副作用。
最后但同样重要的是,每当你替换一个函数的原型属性时,总是建议恢复这个新原型对象的constructor属性,否则它会指向错误的函数。
在您的示例中,由于您将NewBox.prototype 替换为Box 的新实例,因此NewBox.prototype.constructor 属性将指向Box,(您的实例受到影响,例如a.constructor === Box; // true)而不是@ 987654350@ 如您所料,我们需要将其设置回来,例如:
NewBox.prototype = someObject; // as any of the examples above
NewBox.prototype.constructor = NewBox;
您可以将这些细节抽象成一个函数,就像我在上面的 inherit 函数中所做的那样:
function inherits(child, parent) {
var obj, Tmp = function () {};
Tmp.prototype = parent.prototype;
obj = new Tmp();
child.prototype = obj;
child.prototype.constructor = child;
}
//...
// instead of setting the `NewBox.prototype` manually
inherits(NewBox, Box); // "NewBox inherits from Box"
//...