4

I've run into this behavior after using JS for a few months. I'm very puzzled because of my Java background: I create a class and make subclasses. Call a subclass' constructor won't call the parent constructor. Ok, I read about this behavior, it seems normal, right?

See this jsfiddle example to help me clarify.

So to have my subclass constructor run each of its parent constructor, I'm adding the following (see jsfiddle example

Ok, seems to work better this way. Now, I'm wondering about the following; Is there a way to specify wich is the superclass without trigger its constructor? Like for instance the following runs the Node() method:

GameObject.prototype = new Node();
GameObject.prototype.constructor=GameObject;

(see updated jsfiddle example)

I can't help but feel I'm not doing it right. As my real model is layered across 7 subclasses, there's a total of 21 calls to my constructors (6 + 5 + 4 + 3 + 2 + 1 = 21).

Am I doing something wrong? Thanks for your time!

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Jem
  • 6,226
  • 14
  • 56
  • 74

4 Answers4

2

You're not doing anything wrong, per-se. This is the expected behavior given your code. You can, however, use an approach similar to the one described in "Simple JavaScript Inheritence" by John Resig. Another discussion of a similar approach can be found here on stackoverflow.

Community
  • 1
  • 1
Ken Browning
  • 28,693
  • 6
  • 56
  • 68
1

You don't need to call the parent's constructor just to setup the inheritance chain. See http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

The following is bad, runs the parent's constructor just to setup the prototype chain

GameObject.prototype = new Node();
GameObject.prototype.constructor = GameObject;

The better way is to use a surrogate constructor that attaches the prototype without instantiating the "super class".

// Surrogate constructor
var TempCtor = function(){};
TempCtor.prototype = Node.prototype;
// Setup the prototype chain without side effects
GameObject.prototype = new tempCtor();
GameObject.prototype.constructor=GameObject;

And you need to make sure you call the parent constructor from the subclass

function GameObject() {
    // Call the parent's constructor
    Node.call(this);
}

I've updated your jsfiddle with an example that shows the correct way to setup inheritance http://jsfiddle.net/2caTD/5/

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
1

My understanding is that JavaScript doesn't naively implement classes the way traditional languages like C++, Java, and C# do. I think you can get the behaviour you want by using a JavaScript framework that imposes the behaviors you are used to in langauges like Java.

Moo Tools is one such framework: http://mootools.net

Luis Perez
  • 27,650
  • 10
  • 79
  • 80
1

Generally, you're doing it right. But your constructor function creates properties on its instances and those properties get assigned to the inheriting constructor's prototype.

Subclass.prototype.animations, for example are on the prototype, shared by all further instances of Subclass. From your code it seems like you intended these animations to be created anew for each instance.

How to resolve this problem? Don't use constructor functions at all. Use object literals and Object.create.

var Node = {
    init: function () { this.animations = []; },
    doSomething: function () { console.log(this.animations); }
};

var GameObject = Object.create(Node);
GameObject.doSomethingElse = function () { this.init(); this.doSomething(); }

Instantiate the same way you inherit:

var gameObj = Object.create(GameObject);
gameObj.doSomethingElse();

It shouldn't be more difficult than that.

See Combining inheritance with the module pattern.

Community
  • 1
  • 1
katspaugh
  • 17,449
  • 11
  • 66
  • 103
  • Hey that sounds great, I like this idea of having a separate 'init' method. thanks! – Jem Jan 01 '12 at 21:37
  • So... Just don't use constructors? This is not a good way to fix the problem. The correct way is to use a different technique which doesn't involve calling the parent's constructor just to setup inheritance http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html – Ruan Mendes Mar 25 '13 at 19:20
  • Also, `this.animations` is not set on the prototype, it's done on the object itself, writes are always on the object, never on the prototype (unless you do `Constructor.prototype.animations = []`), lastly, the suggestion to use `[]` is OK, but a better suggestion would have been to use `{}` since the OP is not using it as an array, but it's actually a map – Ruan Mendes Mar 25 '13 at 19:41
  • @JuanMendes, `animations` becomes a property of the `Redhead` prototype, when he does `Redhead.prototype = new GameObject();`. I'll edit my answer to be express my take on (the absence of) constructors. – katspaugh Mar 25 '13 at 20:36
  • @Katspaugh I see, it's on the prototype because it's calling the constructor to setup inheritance and the instance of the parent is what gets attached to the prototype. Sorry, I should have realized that... – Ruan Mendes Mar 25 '13 at 20:46
  • @JuanMendes, it's OK. I also see what you mean by the temporary constructor technique. May be useful! – katspaugh Mar 25 '13 at 20:48