说我有两个构造函数:
A = function () { this.x = 'x'; }; A.prototype.a = 'a'; B = function () { this.y = 'y'; }; B.prototype.b = 'b';
如何创建一个将继承自的对象ab
两者的原型?所以下面的例子将起作用:
ab.a === 'a'; // true ab.b === 'b'; // true A.prototype.a = 'm'; ab.a === 'm'; // true B.prototype.b = 'n'; ab.b === 'n'; // true
谢谢
解决方法
你不能,只有一个原型链.你基本上有三个选择:
从一个继承,复制另一个
在单个对象上具有属性方面所能做的就是从其中一个原型继承并复制另一个属性.显然这不是你想要的,因为你没有复制属性的实时参考方面,但是你可以在单个对象上拥有这些属性.
组成
另一种选择是组成:
var ab = { aness: new A(),bness: new B() }; ab.aness.a === 'a'; // true ab.bness.b === 'b'; // true A.prototype.a = 'm'; ab.aness.a === 'm'; // true B.prototype.b = 'n'; ab.bness.b === 'n'; // true
所以现在,ab作为A方面(在其aness属性中称之为“A-ness”),以及在其bness属性中的B方面(称之为“B-ness”).
通常当人们认为“我需要多重继承”时,组合是一个很好的选择(即使在允许多重继承的系统中).并非总是如此,但经常.
如果你需要为ab的A-ness或B-ness添加函数,这些函数也可以访问另一个方面,你可以使用闭包来实现.例如,如果您将对象传递给期望查看A实例并调用其foo函数的第三方库,并且我们希望基于B方面的某些状态在foo中执行不同的操作,则会出现这种情况. .例如:
function AB() { var aness,bness; this.aness = aness = new A(); this.bness = bness = new B(); // `foo` returns the `a` property of our composite if // it's been changed; otherwise,it returns the `b` // property of our composite. aness.foo = function() { // We want to use `A`'s normal `foo` unless our // B-ness `b` property is 42 for some reason. if (bness.b === 42) { // Our magic number,handle locally. return "The answer"; } // Not our magic number,let `A` handle it return A.prototype.foo.call(this); }; } var ab = new AB();
但要注意上面的模式,因为它为AB构造函数生成的每个实例创建了一个新函数.如果有很多,它可能会成为一个内存问题.
在这一点上,我们开始偏向继承链和超级调用,我在this blog post中更详细地讨论了这一点.
将B链接到A.
如果你是A和B的设计者,B从B继承可能是有意义的,然后你的ab可以由B构造函数创建:
A = function () { this.x = 'x'; }; A.prototype.a = 'a'; B = function () { this.y = 'y'; }; B.prototype = new A(); B.prototype.b = 'b'; ab = new B(); ab.a === 'a'; // true ab.b === 'b'; // true A.prototype.a = 'm'; ab.a === 'm'; // true B.prototype.b = 'n'; ab.b === 'n'; // true
…但这意味着所有B对象也是A对象,可能不是您想要的.
偏离主题:我没有在上面假设他们不存在的原因(例如,他们已经在你没有展示的代码中声明它们)的情况下添加变量.
偏离主题2:除非你有充分的理由,否则我总是recommend using named functions而不是匿名的(你分配给A和B的函数是匿名的).