问题是您不能轻易地为B 创建原型对象,因为无法调用A 的构造函数。这是因为在执行new B 之前,构造函数的参数是未知的。您需要一个虚拟构造函数来为B 构造一个原型,该原型链接到A 的原型。
B.prototype = (function(parent){
function protoCreator(){};
protoCreator.prototype = parent.prototype;
// Construct an object linking to A.prototype without calling constructor of A
return new protoCreator();
})(A);
一旦你设置好了B的原型对象,你需要确保在B的构造函数中调用A的构造函数。
function B(x, y) {
// Replace arguments by an array with A's arguments in case A and B differ in parameters
A.apply(this, arguments);
}
您现在应该可以通过调用 new B(x, y) 来实例化 B。
如需在A 中包含参数验证的完整内容,请参阅a jsFiddle。
在您的原始代码中,您正在设置B.prototype.constructor = B。我不明白你为什么要这样做。 constructor 属性不影响prototype 属性负责的继承层次结构。如果你想在 constructor 属性中包含命名构造函数,你需要从上面扩展一点代码:
// Create child's prototype – Without calling A
B.prototype = (function(parent, child){
function protoCreator(){
this.constructor = child.prototype.constructor
};
protoCreator.prototype = parent.prototype;
return new protoCreator();
})(A, B);
使用B.prototype 的第一个定义,您会得到以下结果:
var b = new B(4, 6);
b.constructor // A
console.info(b instanceof A); // true
console.info(b instanceof B); // true
使用extended version,您将获得:
var b = new B(4, 6);
b.constructor // B
console.info(b instanceof A); // true
console.info(b instanceof B); // true
不同输出的原因是instanceof 跟踪b 的整个原型链并尝试为A.prototype 或B.prototype(在另一个调用中)找到匹配的原型对象。 b.constructor 原型确实是指用于定义实例原型的函数。如果您想知道为什么它不指向protoCreator,这是因为它的原型在创建B.prototype 期间被A.prototype 覆盖。 the updated example 中显示的扩展定义将 constructor 属性修复为指向更合适(因为可能更符合预期)的功能。
对于日常使用,我建议完全放弃使用实例的constructor 属性的想法。请改用instanceof,因为它的结果更容易预测/预期。