7

I noticed that every tutorial on how to do JavaScript inheritance does this:

SubClass.prototype = new SuperClass();

But this will create a single instance of the super class and share it among all the instances of the sub class.

The problem is that I would like to pass arguments to the super class constructor which originate from arguments passed to the sub class.

In Java this would be done like this:

class SubClass extends SuperClass {
  public SubClass(String s) {
    super(s);
  }
}

I tried doing something like this:

function SubClass(args) {
  this.constructor.prototype = new SuperClass(args);
}

But this will not work. So is there a way to do this in JavaScript?

mtanti
  • 794
  • 9
  • 25

5 Answers5

6

A common pattern is the following:

A temporary constructor is created, which inherits from the parent constructor's prototype. The child constructor's prototype is then set to an instance of the temporary constructor.

function inherits(Child, Parent) {
    var Tmp = function() {};
    Tmp.prototype = Parent.prototype;
    Child.prototype = new Tmp();
    Child.prototype.constructor = Child;
}

Inside the child constructor you then have to call the parent's constructor:

function Child(a, b, c) {
    Parent.call(this, a, b);
}

inherits(Child, Parent);

// add prototype properties here

Inside this function call, this will refer to the new object which gets created when you call new Child(), hence, whatever initialization is performed inside Parent, it is applied to the new object we pass.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • I don't understand why the "inherits" function is necessary. Why not do as http://stackoverflow.com/a/8736207/652460 suggests and do everything as usual except for using the "Parent.call(this, args)" line? I know that I asked for a way around creating new instances but from what I'm gathering, the state of the parent class instance will be different for different instances of sub class. – mtanti Jan 05 '12 at 01:40
  • 1
    I don't understand your last sentence. But anyways, doing something like `Child.prototype = new Parent()` works as long as `Parent` does not expect (requires) any arguments. In addition, it makes the code a bit cleaner/clearer IMO, but that might be subjective. Major libraries such as the Google Closure Library and YUI provide such a function. – Felix Kling Jan 05 '12 at 09:29
  • @mtanti I was wondering that to. Without the temporary constructor (Tmp) you will end up calling the parent constructor twice - Child.prototype=new Parent(), function Child(a,b,c){Parent.call(this, a, b);}, and in the first instance you won't have any parameters to pass onto the parent constructor. – Mark Horgan Nov 24 '12 at 19:55
2

But this will create a single instance of the super class and share it among all the instances of the sub class.

Yes, that's how inheritance works in JavaScript.

So is there a way to do this in JavaScript?

Not without horribly subverting/twising/misusing the existing paradigm. I recommend taking a different approach to implementing whatever you're aiming for.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • But is there a way to avoid rewriting code to initialize the variables in the super class every time I write a new sub class? What if I write sub sub classes? Will I have to initialize all the variables of all the ancestors? – mtanti Jan 05 '12 at 00:48
  • Instead of variables in the super class, it sounds like you should use _functions_ that the sub class can call. Perhaps even allow for a no-arg version (which the super class would use) and a >0-arg version the sub classes would use. – Matt Ball Jan 05 '12 at 00:54
2

This is how I have always done it.

// Parent object
function Thing(options)
{ 
    //do stuff
}

Thing.prototype.someMethod = function(){
    // some stuff
   console.log('hello');
}

// child object which inherits from the parent
function OtherThing(options)
{       
    Thing.call(this, options);
    // do stuff for otherthing
}

OtherThing.prototype = new Thing();

OtherThing.prototype.someMethod = function(){
   // call things original function
   Thing.prototype.someMethod.call(this);

   // now do anything different
   console.log('other thing says hi');
}


var testObj = new OtherThing();
    testObj.someMethod();

Live Demo

Loktar
  • 34,764
  • 7
  • 90
  • 104
0

With Object.create() it is now possible to simplify "temporary constructor" pattern. Here's an example right from the doc - Classical inheritance with Object.create():

// Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
astef
  • 8,575
  • 4
  • 56
  • 95
0

Another way would to get rid of the class-like (but not class-based) inheritance that involves the use of constructor.

Use Object.create along with Object.defineProperties. This is based on the native prototype-based inheritance system that JavaScript follows internally.

You can find more information on it on MDN and ECMAScript specs.

These methods however works only in ECMAScript 5 compliant browsers. This excludes IE8 and older. Fortunately, IE9 supports it and as does the rest of the major browsers. In long run, I think this would be the way to go.

Golmaal
  • 669
  • 5
  • 8