Inheritance In JavaScript

Published by Marco on in Web: HTML/CSS/JS

Objects in JavaScript showed you how to build and instantiate classes in JavaScript. The flexible prototype mechanism can also be used to effect a form of inheritance.

Assigning an Ancestor

Since an object definition is simply a function call which applies properties and methods to a generic object, inheritance is a series of chained function calls, all acting as constructors. The descendent simply calls the function for its ancestor, so it can set up inherited methods and properties. The example below shows how to assign the base class:

function BaseClass ()
{
  // initialize BaseClass properties
}

MyClass.prototype = new BaseClass;

function MyClass (n)
{
  // initialize MyClass properties
}

It is customary to declare classes and inheritance in usage order, to ensure browser compatibility.

Redefining Methods

Since methods are attached to an object as properties, they can easily be overridden by simply re-assigning the property. This emulates the polymorphism we expect from more strongly-typed languages. The example below uses the prototype syntax to declare methods for the two classes defined above.

BaseClass.prototype.update = function ()
{
  this.printName ();
}

MyClass.prototype.update = function ()
{
  this.printName ();
  this.printAddress ();
}

If the update() method is called on a MyClass object, it prints both the name and address, as expected.

Calling Ancestor Methods

The code above raises another question: how can you call inherited methods? It would be nice to be able to call the inherited version of update in order to execute printName() instead of repeating the code in the descendent implementation. The solution is again relatively obvious, but not elegant: create a property of type BaseClass and call its methods through this reference. The final definition of MyClass is shown below:

MyClass.prototype = new BaseClass;
			
function MyClass (n)
{
  this.parent = new BaseClass ();
}

MyClass.prototype.update = function ()
{
  this.parent.update ();
  this.printAddress ();
}

Note that this technique uses a separate copy of the ancestor — it will not have access to the shared properties set on the descendent unless they are explicitly synchronized. That is, if in the code above, printName() accesses the Name property of the object, it will use the Name from parent instead of from this. Nonetheless, it can still be useful when used with care.

See the Countdown Timer Object example for a real-world use of inheritance in JavaScript.