Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prototypical Inheritance calls constructor twice

I'm working on a JavaScript project that uses Prototypical Inheritance. The way that I decided to use it is the following:

var MySuperClass = function (param) {
    this.prop = param;
};
MySuperClass.prototype.myFunc = function () {
    console.log(this.prop);
};

var MySubClass = function (param) {
    MySuperClass.call(this, param);
};
MySubClass.prototype = new MySuperClass();
MySubClass.prototype.constructor = MySubClass;

var obj = new MySubClass('value');
obj.myFunc();

With the emphasis on the inheritance.

The issue with this is that if I put a console.log in the constructor of each class (the super and the sub), the super class is called twice, once when it is passed into the subclass with MySubClass.prototype = new MySuperClass(); without any parameters and once with parameters when it is 'constructor stolen' in the constructor of the sub class.

This can cause errors if I then try to save those parameters (meaning that I have to add logic to deal with empty params).

Now if I do this:

var MySubClass = function (param) {
    MySuperClass.call(this, param);
};
MySubClass.prototype = MySuperClass;
MySubClass.prototype.constructor = MySubClass;

Everything seems to work correctly but I've never seen anyone do this before (in my Googl'ing).

Can anyone explain to me if and how the 2nd one is incorrect (it seems to be similar to the Crockford inheritance function) and how to fix the 1st one to not fire twice if it is please?

like image 988
obie Avatar asked Nov 02 '12 15:11

obie


1 Answers

Doing this is not a correct solution:

MySubClass.prototype = MySuperClass;

You're setting the function itself as the prototype instead of the prototype object, so you're not inheriting what you'd expect.


But you are right. Doing this does invoke the constructor, which can cause problems.

MySubClass.prototype = new MySuperClass();

The solution is to use Object.create to set up the inheritance. It gives you a new object that inherits from the object provided, but doesn't invoke any constructor.

MySubClass.prototype = Object.create(MySuperClass.prototype);

Now you have an object assigned to MySubClass.prototype that inherits from MySuperClass.prototype, but you never had to actually invoke the constructor.


Non ES5 compliant implementations won't support Object.create, but you can make a (partial) shim for it.

if (!Object.create) {
    Object.create = function(proto) {
        function F(){}
        F.prototype = proto;
        return new F();
    };
}

Again, this is not a full shim, but it emulates just enough to be able to make inherited objects without having to invoke the constructor that references the prototype object.

like image 185
I Hate Lazy Avatar answered Nov 14 '22 23:11

I Hate Lazy