user443946
user443946

Reputation: 845

Javascript multiple inheritance

can anyone please help with the below code. I am trying to understand multiple inheritance not sure why its not working. BTW below if the code for multiple inheritance. Thanks

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

    <title>Test Doc</title>
    <script type="text/javascript">
    function classX(){
        this.messageX="this is X Message";
        this.alertX=function(){
            alert(this.messageX);
        };
    }
    function classY(){
        this.messageY="this is Y Message";
        this.alertY=function(){
            alert(this.messageY);
        };
    }
    function classZ(){
        classX.apply(this);
        classY.apply(this);
        this.messageZ="this is Z Message";
        this.alertZ=function(){
            alert(this.messageZ);
        };
    }
    var abjz=new classZ();
    objz.alertZ();
    abjz.alertX();
    </script>
</head>

<body>


</body>
</html>

Upvotes: 6

Views: 10953

Answers (7)

A Bantly
A Bantly

Reputation: 89

In the book Beginning Node.js by Basarat Syed, he shows an inheritance pattern. This code demonstrates his way of setting up the prototype chain. It uses the util module to as a helper to link the prototype chains.

From page 91, "Javascript supports prototypical inheritance. Chapter 2 of his book explains how a prototype works. In JavaScript, a member is looked up on the current item (such as item.foo), which is followed by its prototype (item.proto.foo), which is followed by it prototype's prototype (item.proto.proto.foo), an so on until the prototype itself (for example, item.proto.proto.proto) is null." - Basarat Syed

Note: The stack overflow editor stripped of the "__" prefix and suffix from proto.

Sample code. Base class is Animal, Bird class is derived from Animal, and Superman class is derived from Bird.

var inherits = require('util').inherits;

// Animal class, the parent
function Animal(name){
    this.name = name;

    // Additional initialization code
}

Animal.prototype.walk = function(destination){
    console.log(this.name,'is walking to',destination);
}

Animal.prototype.eat = function(food){
    console.log(this.name,'is eating',food);
}

// Bird class, child of Animal
function Bird(name){
    // call the Animal constructor
    Animal.call(this,name);

    // Additional initialization code
}

Bird.prototype.fly = function(destination){
    console.log(this.name,'is flying to',destination);
}

// Setup the prototype chain from child Bird to parent Animal
inherits(Bird,Animal);

// Superman class, child of Bird
function Superman(name){
    // Call the Bird constructor
    Bird.call(this,name);

    // Additional initialization code
}

Superman.prototype.jump = function(destination){
    console.log(this.name,'jumped over a',destination);
}

// Setup the prototype chain from child Superman to parent Bird
inherits(Superman,Bird);

// Create the parent instance
var animal = new Animal('elephant');
animal.walk('melbourne');
animal.eat('grass');

// Create the child of animal instance
var bird = new Bird('sparrow');
bird.walk('sydney');
bird.fly('melbourne');
bird.eat('seeds');

// Create the child of bird instance
var superman = new Superman('Clark Kent');
superman.fly('Gotham');
superman.walk('Daily planet');
superman.jump('Building');
superman.eat('Hot dogs');

Output:

elephant is walking to melbourne
elephant is eating grass
sparrow is walking to sydney
sparrow is flying to melbourne
sparrow is eating seeds
Clark Kent is flying to Gotham
Clark Kent is walking to Daily planet
Clark Kent jumped over a Building
Clark Kent is eating Hot dogs

Upvotes: 0

delaynomore
delaynomore

Reputation: 11

You can do it by creating proxies around prototypes in all the chains in the multiple inheritance tree ( in total, the tree ), and then flattening this tree and linking all these proxified prototypes in the preorder DFS traversal. You must then update [Symbol.hasInstance] on every constructor in the inheritance tree to say that this constructor does have this instance. I'm working on this here: https://github.com/dosaygo-coder-0/postjs/blob/master/posttypes/src/mixOf.js

Currently ( October 12 2016 ), the above ideas are not fully implemented.

Upvotes: 1

Mateusz Charytoniuk
Mateusz Charytoniuk

Reputation: 1897

Try this library which simplifies multiple inheritance: https://github.com/meddler/inherit (see: https://github.com/meddler/inherit/blob/master/test/module/inherit/from.js#L19)

Upvotes: 0

nicolas-van
nicolas-van

Reputation: 1051

JavaScript does not give access to multiple inheritance out of the box.

To use it, you could use a class system that allow multiple inheritance like Ring.js.

Upvotes: 1

kzh
kzh

Reputation: 20598

JavaSript does not have true multiple inheritance. You can inherit from only one prototype and then copy the rest of the properties that you want. You can test this by using the instanceof operator.

After fixing the mis-spellings, your demo works, but in actuality, you are not truly inheriting. To do true JS inheritance:

function A(){}
function B(){}
B.prototype = new A;
b = new B;
console.log(b instanceof A, b instanceof B);
//-> true, true

See also

More about JS inheriance on MDN

Quasi-Multiple Inheritance

function ctorX() {
    this.messageX = "this is X Message";
    this.alertX = function() {
        console.log(this.messageX);
    };
}

function ctorY() {
    this.messageY = "this is Y Message";
    this.alertY = function() {
        console.log(this.messageY);
    };
}

function ctorZ() {
    ctorX.call(this); // This is the quasi-multiple inheritance
    this.messageZ = "this is Z Message";
    this.alertZ = function() {
        console.log(this.messageZ);
    };
}
ctorZ.prototype = new ctorY; // This is the actual inheritance

var objz = new ctorZ();
objz.alertZ();
objz.alertY();
objz.alertX();

console.assert(objz instanceof ctorZ, 'objz is not instance of ctorZ');
console.assert(objz instanceof ctorY, 'objz is not instance of ctorY');
console.assert(objz instanceof ctorX, 'objz is not instance of ctorX');
//The last assert will fail since there is no true multiple inheritance

Demo of Quasi-Multiple Inheritance

Avoid Calling the Super Constructor

HMR brought up the point that in some instances, a user wants to inherit from a particular constructor, but the super-constructor requires parameters and will fail w/o them. The way to bypass this is to create a proxy constructor:

function C(x){if(!x) throw new Error;}
function D(){}
function proxyCtor(){/*should be noop*/}
proxyCtor.prototype = C.prototype;
D.prototype = new proxyCtor;

var d = new D;
console.assert(d instanceof C, 'c is not instance of D');
// will err if incorrect, which it's not

Demo

Upvotes: 16

John Middlemas
John Middlemas

Reputation: 21

Your code does not cause inheritance of classX and classY by classZ, it merely copies over their properties/methods.

Object.getOwnPropertyNames(abjz)

reveals:-

messageX,alertX,messageY,alertY,messageZ,alertZ

But for inheritance you want the alert methods to stay only in their respective classes so that any changes to them will be reflected in abjz later. Also, so that there won't be method maintenance issues if you make more instances like abjz.

You could do this:-

var classX = {}
classX.messageX = "this is X Message"
classX.alertX = function(){
    alert(this.messageX)
}

var classY = Object.create(classX)
classY.messageY = "this is Y Message"
classY.alertY = function(){
    alert(this.messageY)
}

var classZ = Object.create(classY)
classZ.messageZ = "this is Z Message"
classZ.alertZ = function(){
    alert(this.messageZ)
}

var abjz = Object.create(classZ)

which is equivalent to:-

function classX(){}
classX.prototype.messageX = "this is X Message"
classX.prototype.alertX = function(){
    alert(this.messageX)
}

function classY(){}
classY.prototype = classX.prototype
classY.prototype.messageY = "this is Y Message"
classY.prototype.alertY = function(){
    alert(this.messageY)
}

function classZ(){}
classZ.prototype = classY.prototype
classZ.prototype.messageZ = "this is Z Message"
classZ.prototype.alertZ = function(){
    alert(this.messageZ)
}

var abjz = new classZ()

Both should output:-

alert( Object.getOwnPropertyNames(abjz) ) //
abjz.alertX()                             // this is X Message
abjz.alertY()                             // this is Y Message
abjz.alertZ()                             // this is Z Message

So now abjz inherits from classZ which inherits from classY which inherits from classX in a linear prototype chain like so:-

abjz --> classZ --> classY --> classX

This is not multiple inheritance though. To get that, abjz needs to inherit directly from each of classX, classY and classZ with no chain, i.e.

abjz --> classZ
abjz --> classY
abjz --> classX

Unfortunately the JS prototype chain system does not permit this, and the flexible benefits of multiple inheritance are killed off by the ordered prototype chain. For example if you also wanted an instance cdef to inherit just from classZ and classX:-

cdef --> classZ --> classX

then in JS the classZ prototype must be changed from classY to classX and that messes up the abjz instance. Whereas in multiple inheritance:-

cdef --> classZ
cdef --> classX

classZ remains nicely unchnaged because there is no awkward chain to deal with.

Upvotes: 1

Pointy
Pointy

Reputation: 413702

You misspelled "abjz" in the call to "alertZ()".

With that corrected, the code works fine, as far as I can tell (two alerts show up, one for Z and one for X).

Upvotes: 6

Related Questions