JavaScript多继承的高效解决方案

JavaScript多继承的高效解决方案,javascript,oop,inheritance,mixins,composition,Javascript,Oop,Inheritance,Mixins,Composition,为什么这个问题不是重复的 这个答案并不能解决我的问题(尽管它被标记为我上一个问题的副本),因为它不可扩展,因为它违反了DRY原则 要使其工作,必须手动引用每个方法,如下所示: Foo2.prototype.a = function() { /*code...*/}; Foo2.prototype.b = function() { /*code...*/}; Foo2.prototype.c = function() { /*code...*/}; Foo2.prototype.d = funct

为什么这个问题不是重复的

这个答案并不能解决我的问题(尽管它被标记为我上一个问题的副本),因为它不可扩展,因为它违反了DRY原则

要使其工作,必须手动引用每个方法,如下所示:

Foo2.prototype.a = function() { /*code...*/};
Foo2.prototype.b = function() { /*code...*/};
Foo2.prototype.c = function() { /*code...*/};
Foo2.prototype.d = function() { /*code...*/};
//and so on and so on...
如果我有几十个包含几十个方法的类呢?我真的应该在源代码中一次又一次地为每个类手动复制粘贴相同的引用吗?虽然此解决方案只适用于极少量的类,但它在使用数十个或数百个类的大型应用程序中不可用

我试图解决的问题

我正在尝试使用
new
关键字实例化必须继承
Animal
Flying\u object
的所有属性和方法的对象

var objA = new Fish(),
    objB = new Bird(),
    objC = new UFO();
棘手的部分是
动物
飞行物体
不能有父子关系

我知道JavaScript没有为多重继承实现本机方法,所以我发布这个问题是为了获得一些帮助,找到一个自定义的、可伸缩的解决方案来解决这个问题

代码示例和预期行为

var Living_being = function() { this.className = 'Living_being'; };

var Animal = function() {
    this.className = 'Animal';
    this.vector = {x: 0, y: 0};
}
Animal.prototype = new Living_being();
Animal.prototype.getClassName = function() { console.log('Instance of... '+ this.className); };
Animal.prototype.get_vector = function() { console.log(this.vector); }

var Flying_object = function() {
    this.className = 'Flying_object';
    this.value = 'some value';
}
Flying_object.prototype.getClassName = function() { console.log('Instance of... '+ this.className); };
Flying_object.prototype.get_val = function() { console.log(this.value); }

// So far so good...
var UFO = function() {};
UFO.protoype = new Flying_object(); //classical inheritance
var Fish = function() {};
Fish.protoype = new Animal(); //classical inheritance
// Now the tricky part: how to make Bird share all of the methods and properties of Animal and Flying_object ?
var Bird = function() {};
Bird.prototype = new ....(); //pseudocode where .... is a class containing all the properties of Animal and Flying_object

var instance = new Bird();

//expected result:
instance.getClassName();//--> Instance of...
instance.get_vector();  //--> {x: 0, y: 0}
instance.get_val();     //--> 'some value'
这就是我被困的地方。如何使鸟同时继承
动物
飞行对象

任何洞察都会非常有用。

如果您需要从几个类继承,您可以使用jquery函数
$.extend({})从Animal和Ufo扩展原型Bird。
示例
$.extend(Bird.prototype、Animal.prototype、UFO.prototype)
或者您可以创建自定义扩展函数。如果名称属性或函数具有相同的名称,则将重写它们


我从文档中了解到这一点:使用Object.assign()只扩展可枚举属性。Object.assign()方法只将可枚举属性和自身属性从源对象复制到目标对象。它在源上使用[[Get]],在目标上使用[[Set]],因此它将调用getter和setter。因此,它可以指定属性,而不仅仅是复制或定义新属性。如果合并源包含getter,则这可能不适合将新属性合并到原型中。用于将属性定义(包括其可枚举性)复制到原型对象中。应改用getOwnPropertyDescriptor()和Object.defineProperty()。

以下是我在某个时候提出的一个可行解决方案,后来放弃了,因为我认为可能有更好的解决方案

@Mörre:我不确定这是你在评论中建议我做的:这就是你所谓的对象组合吗?还是我在这里出了问题

演示:


JavaScript不支持多重继承的概念。它也不实现mixin和/或基于特征的合成的语法。但与前者不同,后者可以通过基于功能和委托的混合模式来实现

因此,首先需要弄清楚可组合对象系统的哪些部分应该构建“是a”关系,哪些部分是可能被对象系统的不同部分/级别重用的行为(“可以做”/“有a”)

OP已经完成了这项工作。下面将提供的示例代码将通过提供一些行为的实现,如
with livingbeingbasics
with flyingability
,来引入不同的基于函数的混合模式。。。第一个mixin覆盖OP的
Living\u being
类,第二个mixin覆盖
Flying\u object

为了更好地重用代码,有两个额外的混合,分别是带有ExposeClassName的
和带有ExposeVector的
混合,出于演示的原因,它们组成了带有ExposeClassName和Vector的
混合体

从这个可能的基础设置(遵循OP的示例),可以继续塑造类

对于
动物
一级可自由选择混合成分的发生地点。按照提供的原始示例,类/原型级别的组合是更好的选择,而不是从构造函数内部应用构造/实例化时的行为

在将ExposeClassNameandVector应用于
之后,任何通过原型委托的动物实例都可以在
getClassName
getVector
以及
代谢
复制
调用。因此,此时,mixin组合(通过
调用
原型的显式委托)和继承(通过原型链自动运行委托)都发生了

Fish
类很容易实现。与OP的例子一样,我们只是通过
Fish.prototype=new Animal遵循简化的继承模式。此外,正如
Animal
基类的特点一样,类的名称被分配给它的
prototype
对象

Bird
重复了
Fish
的基本模式,但其自身的
向量
属性现在是三维的,而不是原型的二维属性。由于一只普通的鸟被认为以某种方式具有飞行行为,原型必须从具有飞行能力的鸟那里获得

按照OP的例子,
Ufo
也需要有飞行能力。像鸟一样,不明飞行物也必须具有自己的三维
矢量
特性。因此,属性在构造/实例化时被分配,所有需要的行为都从
和exposeclassname和vector
以及
和flyingability
应用到
Ufo
function mix(classA, classB) {
    var instanceA = new classA(),
        instanceB = new classB();
    for (var prop in instanceA) {
        instanceB[prop] = instanceA[prop];
    }
    return instanceB;
}

var Bird = function() { this.className = 'Bird'; };
Bird.prototype = mix(Animal, Flying_object);
var instance = new Bird();