通常当您想要扩展多个对象时,您必须查看您的设计是否正确。对象是另一个对象吗?
例如,猫是动物,猫可以移动。从 Movable 扩展 Cat 是错误的,因为 Cat 不是可以移动的 Movable,所以它应该实现 Movable 或保留 Movable 的默认实现。
Cat Feline and Animal 的例子很好,但是不用多重继承也可以解决。猫是猫科动物,猫科动物是动物,所以猫没有理由既继承自猫科动物又继承动物动物,你可以让猫继承自猫科动物,而猫科动物继承自动物。
选择的答案涉及混入(实现)的原型部分,但不包括如何初始化实例特定成员。以下是 following answer 的一部分:
使用 mix ins 进行多重继承
有些东西最好不要继承,如果 Cat 可以移动,而不是 Cat 不应该从 Movable 继承。猫不是可移动的,而是猫可以移动。在基于类的语言中,Cat 必须实现 Movable。在 JavaScript 中,我们可以在这里定义 Movable 并定义实现,Cat 可以覆盖、扩展它或者我们它的默认实现。
对于 Movable,我们有特定于实例的成员(例如 location)。而且我们有不是特定于实例的成员(例如函数 move())。创建实例时,将通过调用 mxIns(由 mixin 辅助函数添加)来设置实例特定成员。原型成员将使用 mixin 辅助函数从 Movable.prototype 中的 Cat.prototype 上一一复制。
var Mixin = function Mixin(args){
var i, len;
if(this.mixIns){
i=-1;len=this.mixIns.length;
while(++i<len){
this.mixIns[i].call(this,args);
}
}
};
Mixin.mix = function(constructor, mix){
var thing
,cProto=constructor.prototype
,mProto=mix.prototype;
//no extending, if multiple prototype uhs
// have members with the same name then use
// the last
for(thing in mProto){
if(Object.hasOwnProperty.call(mProto, thing)){
cProto[thing]=mProto[thing];
}
}
//instance intialisers
cProto.mixIns = cProto.mixIns || [];
cProto.mixIns.push(mix);
};
var Movable = function(args){
args=args || {};
//demo how to set defaults with truthy
// not checking validaty
this.location=args.location;
this.isStuck = (args.isStuck===true);//defaults to false
this.canMove = (args.canMove!==false);//defaults to true
//speed defaults to 4
this.speed = (args.speed===0)?0:(args.speed || 4);
};
Movable.prototype.move=function(){
console.log('I am moving, default implementation.');
};
var Animal = function(args){
args = args || {};
this.name = args.name || "thing";
};
var Cat = function(args){
Animal.call(args);
//if an object can have others mixed in
// then this is needed to initialise
// instance members
Mixin.call(this,args);
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Mixin.mix(Cat,Movable);
var poochie = new Cat({
name:"poochie",
location: {x:0,y:22}
});
poochie.move();