JavaScript的inheritance:当构造函数有参数
使用纯JavaScript来做inheritance,这是我通常做的:
function A() {} A.prototype.run = function () {}; function B() {} B.prototype = new A; B.prototype.constructor = B;
由于没有任何参数传入构造函数,新的A没有什么可抱怨的。 现在,如果构造函数有parameter passing,我还没有想出inheritance的好方法。 例如,
function A(x, y) {} A.prototype.run = function () {}; function B(x, y) {} B.prototype = new A; B.prototype.constructor = B;
我可以传递一些任意值,如:
B.prototype = new A(null, null);
在某些情况下,我可能需要在A的构造函数中validationx和y。在某些极端情况下,检查x或y时需要抛出错误。 那么B就没有办法使用新的A.
有什么build议么?
谢谢!
那么,如果你想使B.prototype
成为一个inheritance自B.prototype
的对象而不执行A
构造函数,为了避免所有可能的副作用,你可以使用一个虚构的构造函数来完成它,例如:
function tmp() {} tmp.prototype = A.prototype; B.prototype = new tmp(); B.prototype.constructor = B;
你可以创build一个函数来封装这个新对象的创build逻辑,例如:
function inherit(o) { function F() {}; // Dummy constructor F.prototype = o; return new F(); } //... B.prototype = inherit(A.prototype); B.prototype.constructor = B;
如果您的目标是现代浏览器,则可以使用ECMAScript 5 Object.create
方法来达到同样的目的,例如:
B.prototype = Object.create(A.prototype); B.prototype.constructor = B; //..
问题是你不能轻易地为B
创build一个原型对象,因为不能调用A
的构造函数。 这是由于在执行new B
之前构造函数的参数是未知的。 你需要一个虚拟构造函数来构造一个连接到A
的原型的B
的原型。
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
参数validation的完整相同请参见jsFiddle 。
在你原来的代码中,你正在设置B.prototype.constructor = B
我不明白你为什么这样做。 constructor
属性不会影响prototype
属性负责的inheritance层次结构。 如果你想在constructor
属性中包含指定的构造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
随着扩展版本 ,你会得到:
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
(在另一个调用中)find匹配的原型对象。 b.constructor
原型是指用于定义实例原型的函数。 如果你想知道为什么它不指向protoCreator
这是因为在创buildA.prototype
期间,它的原型被A.prototype
所覆盖。 如更新示例中所示的扩展定义将此constructor
属性修复为指向更合适(因为可能更多期望)的函数。
对于日常使用,我build议放弃完全使用实例的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; }
接着
var b = new B( 12, 13 );
现在b
从A
一个实例inheritance而来, A
又inheritance自A.prototype
。
现场演示: http : //jsfiddle.net/BfFkU/
Object.create
没有在IE8中实现,但可以很容易地手动实现它:
if ( !Object.create ) { Object.create = function ( o ) { function F() {} F.prototype = o; return new F(); }; }
这可以放在一个ie8.js
文件中,该文件仅通过条件注释为IE8加载。
虽然这是一个古老的话题,但我还是认为我会回应。 两种方式来做到这一点:
虽然伪古典方式是最stream行的,但它有其不利的一面,因为它需要在子构造函数中调用父构造函数一次,而在inheritance原型的时候需要一次。 此外,孩子的原型将包含父构造函数的所有属性,当调用子构造函数时,它将被覆盖。 我个人的select是原型inheritance 。
1.伪古典inheritance:
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;
2.原型inheritance:
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;