Search code examples
javascriptoopinheritancemixinscomposition

JavaScript efficient solution for multi-inheritance


Why this question is not a duplicate

This answer javascript inheritance from multiple objects does not solve my problem (although it has been marked as a duplicate of my previous question), because it is not scalable as it violates the DRY principle.

For this to work, one would have to manually reference each method like this :

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...

And what if I have dozens of classes containing dozens of methods ? Should I really manually copy-paste the same reference for each and every class over and over again in my source code ? While this solution would work for a very low number of classes, it is just not usable in a large-scale application using dozens or hundreds of classes.

The problem I'm trying to solve

enter image description here

I'm trying to instantiate objects which must inherit all the properties and methods of Animal and Flying_object using new keyword.

var objA = new Fish(),
    objB = new Bird(),
    objC = new UFO();

Tricky part is Animal and Flying_object can NOT have a parent-child relationship.

I know JavaScript doesn't implement native methods for multi-inheritance, so I'm posting this question to get some help finding a custom, scalable solution to this problem.

Code example and expected behavior

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'

This is where I'm stuck. How can I make Bird inherit from BOTH Animal and Flying_object ? Any insight would be greatly apprenciated.


Solution

  • Here is a working solution I came up with at some point and gave up because I though there might be a better solution.

    @Mörre: I'm not sure this is what you advised me to do in the comments: is this what you called object composition ? Or am I going all wrong here ?

    Demo: https://jsfiddle.net/Lau1989/4ba8yrc8/1/

    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();