3

I'm trying to get prototypal inheritance working in the following way:

// Parent constructor
function Parent(obj) {
    this.id = obj.id || 0;
    this.name = obj.name || "";
};

// Child constructor
function Child(obj) {
    Parent.call(this,obj);
    this.type = obj.type || "";
}

Child.prototype = new Parent;

Seems textbook ... but passing obj to both parent and child seems to be causing problems; Parent says obj is undefined when the child tries to prototype via Child.prototype = new Parent;. The only way I can get around this is with this ugly hack:

// 'Hacked' Parent constructor
function Parent(obj) {
    if (obj) {
        this.id = obj.id || 0;
        this.name = obj.name || "";
    }
};

Surely there's a better way, but I can't find an answer anywhere. Please help!!

2 Answers 2

5

Child.prototype = new Parent; creates a new Parent without any parameters and returns its prototype, assigning it to Child.prototype. This approach works well, but the problem is that it only works on parents with 0 parameters (new Parent is the equivalent of new Parent() in this context).

For Parent constructors with parameters, I suggest defining an inherits function to handle your inheritance.

The fix I proposed earlier was that of Child.prototype = Parent.prototype;. This will work, but now Child.prototype is a reference to Parent.prototype rather than an object. In other words, if you add the method hello to the Child, then the Parent also receives that method. Bad times!

The best solution to this problem is to define some inherits function as such:

function inherit(parentPrototype) {
  function F() {};
  F.prototype = parentPrototype;
  return new F;
}

What we're doing here is slightly different than just assigning Parent.prototype to the Child. We're creating a new function which has the parent's prototype and returning a new instance of the function F. So, when you add methods to the Child, you're actually adding them to the prototype of the F function.

To create the Child object now, you'd do:

function Child() {};
Child.prototype = inherit(Parent.prototype); // returns an instance of F

You can then add methods to the Child without affecting the Parent.

Sign up to request clarification or add additional context in comments.

6 Comments

An excellent answer - thank you :) One point of clarification (relating to your hello() method example) ... in my real case, Parent has methods that I obviously want Child to inherit. Is there something special I need to do to enable that since new is no longer used? (e.g. manually assign this, manually prototype the methods to Child, etc.) Thanks again!
Child.prototype = Parent; will just add a function as the prototype object, whose prototype will not be checked. However, if you add the methods directly on the Parent constructor function itself, the child object can reach them, true, but the Parent itself does not work, so that is not really inheritance as I see it.
No, Parent is a reference to a function whose prototype has all the declared Parent methods. When you set the Child prototype to that of the Parent, it gets all those methods. You then add to the Child prototype with your Child-specific methods.
The problem I was referring to is setting up any Child-specific methods BEFORE you've assigned its prototype to that of Parent. Child.prototype = Parent is just like any other assignment; you lose the value previously held in Child.prototype.
My original answer actually had a small mistake in it, please re-read the post now as I've corrected it.
|
0

It's a little more pleasant looking to do:

function Parent(obj) {
    if (!obj) {return;}
    this.id = obj.id || 0;
    this.name = obj.name || "";
}

Your style of inheritance is more according to the "classical" pattern.

You can also do this:

Child.prototype = Parent.prototype;

...but any subsequent additions to Child.prototype, will end up on the Parent prototype too (and vice versa).

Maybe this is why this kind of behavior is often wrapped to return the object directly when needed, in a manner where you can't as easily overwrite the Parent (though you can via the obj.constructor.prototype):

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};

3 Comments

Thanks for the answer. I saw this solution on Crockford's site but didn't fully understand it; I can clearly see the benefits now!
One other thing: If you don't want to bother with type checks or utility methods, you could simply pass in an empty object: Child.prototype = new Parent({}); Also, you can modify or make a new version of the function given by myself and Emmerich to allow the simpler syntax: Child.prototype = inherit(Parent); as well.
Thanks - I've used the inherit/create method you both suggested and it's working well. I need utility methods so the empty object won't work, but nice simple idea all the same.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.