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.
The tools that Javascript provides are:
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 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.
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.
function extend(superType).var intermediateConstructor = function() {};intermediateConstructor.prototype = superType.prototype;return new intermediateConstructor();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.
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.
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
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.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.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..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.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.