Gra*_*hao 46 javascript inheritance prototype-programming
使用纯JavaScript进行继承,这是我通常做的事情:
function A() {}
A.prototype.run = function () {};
function B() {}
B.prototype = new A;
B.prototype.constructor = B;
Run Code Online (Sandbox Code Playgroud)
由于没有参数传递给构造函数,新的A没有什么可抱怨的.现在,如果构造函数有要传递的参数,我还没有想出一个很好的继承方法.例如,
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {}
B.prototype = new A;
B.prototype.constructor = B;
Run Code Online (Sandbox Code Playgroud)
我可以传递一些任意值,如:
B.prototype = new A(null, null);
Run Code Online (Sandbox Code Playgroud)
在某些情况下,我可能需要在A的构造函数中验证x和y.在某些极端情况下,我在检查x或y时需要抛出错误.然后,B无法使用新的A从A继承.
有什么建议?
谢谢!
CMS*_*CMS 23
好吧,如果你想创建B.prototype一个继承自的对象A.prototype,而不执行A构造函数,以避免所有可能的副作用,你可以使用虚拟构造函数来做到这一点,例如:
function tmp() {}
tmp.prototype = A.prototype;
B.prototype = new tmp();
B.prototype.constructor = B;
Run Code Online (Sandbox Code Playgroud)
您可以创建一个函数来封装这个新对象的创建逻辑,例如:
function inherit(o) {
function F() {}; // Dummy constructor
F.prototype = o;
return new F();
}
//...
B.prototype = inherit(A.prototype);
B.prototype.constructor = B;
Run Code Online (Sandbox Code Playgroud)
如果您定位现代浏览器,则可以将ECMAScript 5 Object.create方法用于相同目的,例如:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
//..
Run Code Online (Sandbox Code Playgroud)
问题是你不能轻易创建一个原型对象,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);
Run Code Online (Sandbox Code Playgroud)
一旦你有了B设置的原型对象,你需要确保在构造函数中调用构造A函数B.
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);
}
Run Code Online (Sandbox Code Playgroud)
您现在应该能够B通过调用实例化new B(x, y).
有关包含参数验证的完整相同内容,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);
Run Code Online (Sandbox Code Playgroud)
使用您的第一个定义B.prototype会得到以下结果:
var b = new B(4, 6);
b.constructor // A
console.info(b instanceof A); // true
console.info(b instanceof B); // true
Run Code Online (Sandbox Code Playgroud)
使用扩展版本,您将获得:
var b = new B(4, 6);
b.constructor // B
console.info(b instanceof A); // true
console.info(b instanceof B); // true
Run Code Online (Sandbox Code Playgroud)
不同输出的原因是instanceof跟随整个原型链b并试图找到匹配的原型对象A.prototype或B.prototype(在另一个调用中).该b.constructor原型确实是指用于定义实例原型的功能.如果你想知道为什么它没有指出protoCreator这是因为它的原型A.prototype在创建过程中被覆盖了B.prototype.更新后的示例中显示的扩展定义将此constructor属性修复为指向更合适(因为可能更期望)的函数.
对于日常使用,我建议完全放弃使用constructor实例属性的想法.而是使用,instanceof因为它的结果更可预测/预期.
考虑一下:
function B( x, y ) {
var b = Object.create( new A( x, y ) );
// augment b with properties or methods if you want to
return b;
}
Run Code Online (Sandbox Code Playgroud)
然后
var b = new B( 12, 13 );
Run Code Online (Sandbox Code Playgroud)
现在b继承自一个实例A,而实例继承自A.prototype.
现场演示: http ://jsfiddle.net/BfFkU/
Object.create 在IE8中没有实现,但可以轻松地手动实现它:
if ( !Object.create ) {
Object.create = function ( o ) {
function F() {}
F.prototype = o;
return new F();
};
}
Run Code Online (Sandbox Code Playgroud)
这可以放在一个ie8.js文件中,该文件仅通过条件注释加载到IE8及以下版本.
小智 5
尽管这是一个老话题,但我还是想回应。有两种方法:
尽管Pseudo Classical方法是最流行的方法,但它有缺点,因为它需要在子构造函数中调用一次父构造函数,而在继承原型时调用一次。此外,子级原型将包含父级构造函数的所有属性,无论如何,当调用子级构造函数时,这些属性都会被覆盖。我个人的选择是“ 原型继承”。
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = new A();
B.prototype.constructor = B;
Run Code Online (Sandbox Code Playgroud)
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
Run Code Online (Sandbox Code Playgroud)