Simple Javascript inheritance that works

Computer

Javascript is a prototype-based language which has some slightly unusual semantics if you are used to languages like Java and C#. Classical OO inheritance isn’t trivial in Javascript – at least not conceptually. There are many webpages out there out there offering various solutions. Many of them propose complicated and strange answers to the problem, when actually it’s pretty simple.

Approaches to inheritance in Javascript

The tools that Javascript provides are:

  1. sharing of a function between otherwise unrelated objects
  2. when it is constructed, an object may be assigned a prototype (also an object), which will be used to find any slot (method / property) that cannot be found on the first object

Most of the solutions out there rely heavily on (1), where (2) is actually more appropriate. Why? Only (2) allows you to change the behaviour of a supertype, and have changes reflected in all instances of subtypes. With (1), once the function properties have been copied there is no on-going relationship between types. Plus, though relying on it may indicate a slight design smell, instanceof will only work with a correctly set prototype chain.

The solution

The solution sets up the prototype chain of an object to create inheritance-like behaviour-sharing. Here is the simplest formulation, which does not change any built-in Javascript objects.

function extend(superType) {
    var intermediateConstructor = function() {};
    intermediateConstructor.prototype = superType.prototype;
    return new intermediateConstructor();
}

You use this as a library function to create inheritance relationships.

How it works

You don’t need to understand it in detail, but here’s a quick run-down on how this works. Skip to the next section if you just want to use it.

  1. We need to create a new object that will be used as the prototype for our sub-type, but will have the super-type in its constructor chain. Creating the new prototype is the goal of the function function extend(superType).
  2. We don’t want to stop people using constructors freely but we do need to control the prototype chain, which can only be done via a constructor. So, create a do-nothing constructor: var intermediateConstructor = function() {};
  3. Hook up any objects created by this constructor to the super-type’s prototype (so they’ll inherit super-type behaviour): intermediateConstructor.prototype = superType.prototype;
  4. Finally, call the newly-created constructor to create an empty prototype object whose prototype link points to the super-type prototype and return it: return new intermediateConstructor();

How to use it

Say we have a supertype with an example instance variable property (which we want to set from the constructor) and an example method:

function SuperType(arg) {
    this.property = arg;
}

SuperType.prototype.method = function(arg) {
    alert(this.property + arg);
}

We can create a sub-type which inherits from this. First we need a constructor function. It has to call the supertype’s constructor to perform any supertype-specific set-up.

function SubType(arg, anotherArg) {
    SuperType.call(this, arg);
    this.anotherProperty = anotherArg;
}

Now 1 line of magic. Using our extend function we can create a new prototype that is hooked up to SuperType in its prototype chain, and use this newly-created prototype as the prototype for all instances of SubType. Note that this overwrites the prototype originally set for SubType (which would have inherited from the Javascript standard type Object).

SubType.prototype = extend(SuperType);

Now we can add methods as normal.

SubType.prototype.anotherMethod = function() {
    alert("Another method");
}

etc.

To create a SubType object just do var aSubTypeInstance = new SubType(10, 20) as normal. To see inheritance in action, try calling aSubTypeInstance.method(30)method must be inherited from SuperType for you to see anything.

What about super?

super is a feature of many OO languages that allows you to call the same-named method inherited from a superclass. Some of the other solutions out there put a lot of effort into trying to implement super in Javascript, but there’s no really neat, simple, short answer and if you program carefully you rarely need this feature. Whenever you do need it, I suggest just calling the superclass method directly.

SubType.prototype.overriddenMethod = function(arg1, arg2) {
    // do some SubType-specific stuff, then...
    SuperType.overriddenMethod.call(this, arg1, arg2);
    // do some more SubType-specific stuff
}

The downsides with this approach is that it’s a slightly wordy invocation—super is a bit shorter (though not as short in Javascript as in many other languages)—and it binds SubType to SuperType in more places, so it would be a little harder to change the SubType to inherit from, say, IntermediateType.

What this does that many other approaches get wrong

Updating supertype methods/properties should affect subtype instances.

SuperType.prototype.thisMethodHasBeenChanged = function() {
    return false;
}

var mySubTypeInstance = new SubType();
mySubTypeInstance.thisMethodHasBeenChanged(); // returns false

SuperType.prototype.thisMethodHasBeenChanged = function() {
    return true;
}

mySubTypeInstance.thisMethodHasBeenChanged(); // returns true

aSubTypeInstance instanceof SuperType should be true.

var aSubTypeInstance = new SubType();
aSubTypeInstance instanceof SuperType; // return true

Limitations of this approach

  1. There is no standard way in Javascript to change the prototype link of an object, so changing the prototype chain (relationships between types) dynamically isn’t feasible. For example, once Dog inherits from Organism, no Dog instance can be made to inherit from Animal instead. You can still change the properties of the prototype, so it’s possible to add an eat method to Organism dynamically and have dogs inherit it.
  2. Once you’ve assigned methods / properties to a prototype, MyType.prototype = extend(OtherType) will zap all your changes. So, you need to do this before defining any methods, and… you can only do it once. There’s no way to use the prototype chain to inherit from multiple supertypes.
  3. Although it doesn’t pollute Javascript’s standard objects, extend isn’t itself a very object-oriented API. Peter Marks suggested an improvement which attaches extend to Function.prototype, making a nicer (to some eyes) API. Post a comment if you’d like me to post it.
  4. The rarely-used .constructor property of an object will return the wrong answer when using extend. You can add 1 line to extend to fix that… provided you know the correct constructor to set it to, which here we don’t. Peter’s approach helps a lot with this, but on balance I think using the .constructor property is not a very good idea. Again, post a comment if you want me to drill into this some more.

Other solutions

James Estes independently came up with essentially the same solution. Just as James has done, I took the view that a general super mechanism is not worth implementing; it’s a little complicated and not too useful. (super allows a subtype to access a property – typically a method – of its supertype, and is usually used to access a method that has been redefined in a subtype).

Since I started writing this Kevin Lindsey’s solution has been updated and now also follows the same mechanism I’ve laid out here. You can still read Kevin’s original solution.