6

I am wondering whether it is possible to inherit constructor in javascript. In the following example, I'd like the Moveable to assign x and y arguments to this.x and this.y respectivelly, as I defined in Sprite. Also, what would be the best way (but still short and readable) to define the prototype without creating the instation of ancestor? It would be best to assign it in the class itself, not in the outside scope as I it is now:

function Sprite(x, y) {
    this.x = x ? x : 0;
    this.y = y ? y : 0;     
    this.getPos = function() {
        return {
            x: this.x,
            y: this.y
        };
    };
}

function Moveable(x, y) {

}
Moveable.prototype = new Sprite();
Mikulas Dite
  • 7,790
  • 9
  • 59
  • 99

3 Answers3

6

The standard way to call a superclass constructor is using Function.call:

function Moveable(x, y) {
  Sprite.call(this, x, y);
}

As for the prototype, you can do something like this to chain the prototype without creating an instance of the superclass:

function makePrototype(superclass) {
  function f() { }
  f.prototype = superclass.prototype;
  return new f();
}

Moveable.prototype = makePrototype(Sprite);

This uses a dummy constructor to create an object that shares the same prototype as Sprite, and since that's all JavaScript cares about, instances of Moveable are considered instanceof Sprite.

This isn't "short and readable" as you asked for, but the only other choice is to entirely skip prototypes and assign members directly within the constructor.

Edit: As @Raynos points out, you also want to set the constructor property (which is done by default by JavaScript but is lost as soon as you reset Moveable.prototype):

Moveable.prototype.constructor = Moveable;
casablanca
  • 69,683
  • 7
  • 133
  • 150
  • 2
    You forgot to set the `prototype.constructor` property! – Raynos Feb 13 '11 at 17:22
  • @Raynos: Oops, missed that. Fixed now. – casablanca Feb 13 '11 at 17:28
  • Setting the prototype.constructor is a misleading step that doesn't actually change the constructor - the originally will still be called. All this does is make it so if you are doing fancy equality checks of your classes it will say it is the same. if(this.constructor === Sprite.constructor) – mwilcox Feb 13 '11 at 21:12
  • 1
    @meyertee: `instanceof` depends only on the `prototype` property, it doesn't care about `constructor` -- in fact, nothing in the language cares about it, it's purely a convenience property. – casablanca Feb 13 '11 at 23:11
  • @casablanca, thanks, you're right. I thought there was something about the construtor-prop and the instanceof operator. Removed my misleading comment, sorry. – meyertee Feb 14 '11 at 10:03
6

You'd call the parent constructor like this:

function Moveable(x, y) {
    Sprite.call(this, x, y);
}

I'm afraid there's no short way of setting up the inheritance if you want to use pseudo-classical inheritance, and no way of doing it inside the scope of the constructor function.

You can get around instantiating your base class though, if you construct a temporary empty object. Looks complicated but is commonly used as a helper function (like in the Google Closure Library goog.inherits method from where I more or less copied this):

var inherits = function(childConstructor, parentConstructor) {
  function tempConstructor() {};
  tempConstructor.prototype = parentConstructor.prototype;
  childConstructor.prototype = new tempConstructor();
  childConstructor.prototype.constructor = childConstructor;
};

inherits(Moveable, Sprite);

// instantiating Moveable will call the parent constructor
var m = new Moveable(1,1);
meyertee
  • 2,211
  • 17
  • 16
  • Sorry, I had to vote you down. This doesn't call both constructors. – mwilcox Feb 13 '11 at 21:10
  • I put the vote back, because after re-reading the question I'm not exactly sure what he wants. – mwilcox Feb 13 '11 at 21:21
  • 1
    I think the question is pretty clear and your down-vote not justified. The question is how to setup inheritance and how to call the super constructor when Movable is instantiated, which I both answered. – meyertee Feb 13 '11 at 21:37
  • No, it's not, and no you didn't. Inherit (very basically) means to call both constructors. All your code really does is set arg2's proto to arg1's proto. Nothing is inheriting. – mwilcox Feb 13 '11 at 22:11
  • BTW, I tried to re-vote you but can't unless you change something. Do so and I will because your first block of code is simple and answers the question. – mwilcox Feb 13 '11 at 22:12
  • I think the author of the question is aware of the fact that he has to instantiate Moveable with `var m = new Moveable();` which - when following casablanca's or my example - would in turn call the super constructor. This is pretty standard pseudo-classical inheritance stuff - I'm describing Google standard mechanism for inheritance in the Closure Library. – meyertee Feb 13 '11 at 22:20
1

Think of a function as two pieces: the constructor function and the prototype object. Take two of these function classes and mix them together. Mixing the objects are simple enough, the trick is to mix the constructors.

var Sprite = function(x, y, w, h){
   console.log("Sprite constr:", x, y, w, h);
}

var Moveable = function(x, y, w, h){
   console.log("Moveable constr:", x, y, w, h);
}

var extend = function(class1, class2){
   // here we make a new function that calls the two constructors. 
   // This is the "function mix" 
   var f = function(){
      class1.prototype.constructor.apply(this, arguments);
      class2.prototype.constructor.apply(this, arguments);
   }
   // now mix the prototypes
   f.prototype = library.objectmix(class1.prototype, class2.prototype);
   return f;
}

var MoveableSprite = extend(Sprite, Moveable);
mwilcox
  • 4,065
  • 23
  • 20
  • 1
    A shortcut for "mix two objects together with your favorite library". – mwilcox Apr 26 '11 at 21:57
  • 1
    One shouldn't need a whole library just to do simple inheritance. – rxgx Apr 27 '11 at 19:09
  • It's an example. You can't write your own mixin? – mwilcox May 05 '11 at 20:49
  • the problem with this is that in classical inheritance you don't pass all the arguments in child class constructor to the parent class constructor. in fact, in most cases super() is called implicitly with no arguments in languages like java. in order to pass explicit args to the superclass constructor youd have to explicitly call super – Alexander Mills Sep 12 '15 at 20:47