Javascript Jems - Prototype Inheritance
Written by Ian Elliot   
Monday, 18 October 2010
Article Index
Javascript Jems - Prototype Inheritance
Dynamic inheritance
Prototype chains

Javascript supports inheritance via the prototype mechanism but it's nothing like the class based inheritance that you are familiar with. You can even argue that in a dynamic language inheritance isn't a useful concept.


Javascript Jems on Objects

A complete introduction to Javascript and objects. This article is part of a series that explains how Javascript has a very special approach to objects. You might like to read them in order.

1.   A new take on objects

2.  Object factories, constructors and clones

3. Type and the constructor

4. Javascript Jems - The Prototype
5. Javascript Jems - Prototype Inheritance

 

Banner

 

Now that we have seen the prototype mechanism in action with methods and properties lets take it one stage further and implement Javascript's inheritance mechanism.

It is important to realise that Javascript is a dynamic language and it doesn't make use of classes. Instead objects are the key idea and objects can be changed dynamically. This renders the strict notion of "type" redundant and only a weaker notion of "same constructor" remains. It also weakens the idea of inheritance as objects can inherit a range of methods and properties but then simply add or subtract more. You can't avoid the fact that Javascript objects are dynamic and they are defined at runtime.

Prototype as inheritance

The key idea to using the prototype mechanism as a way to build an inheritance chain is to realise that you don't simply have to add single properties and methods to it.

Why not set the prototype property to a complete new custom object?

In this case the object created by the constructor would essentially "inherit" all of the methods and properties defined in the object used as the prototype.

This is the sense in which the prototype mechanism is all about inheritance.

Let's look at a simple example. Suppose we have a constructor for a 2D point object:

function Point2D()
{
this.x=0;
this.y=0;
this.setPoint = function(x, y){
  this.x = x;
  this.y = y;                              
};
}

Notice that this has two properties, x and y, and a single method to set the properties.

Now we can use this as the base constructor for a 3D point object's constructor:

function Point3D()
{
this.z=0;
}
Point3D.prototype=new Point2D();

This creates an object with a single property of its own that is z but by setting its prototype property to a new instance of Point2D it also has x,y and the setPoint method supplied by the Point2D object.

If you try:

var Points=new Array(10);
for(var i=0;i<10;i++){
Points[i] = new Point3D();
Points[i].z=i;
Points[i].setPoint(i,i);
};
alert(Points[5].x);
alert(Points[5].z);

you will discover that both the x and z properties work as you would expect. Notice that a single copy of the setPoint method is used by all of the instances of Point3D. Also notice that each Point3D object acquires its own personal x and y properties as soon as the setPoint method is called to set them to particular values.

So at the end of the for loop Point3D has three locally implemented properties x, y and z.

That is the prototype object supplies its methods and initially its properties to the receiving object but as the receiving object uses the properties it makes local versions of them.

This is a dynamic language and this is how it should behave.

Overriding methods

It is clear that the setPoint method that Point3D inherits really isn't good enough - it only sets two of the three co-ordinates. In many cases you need to override an inherited function to change the way it works. To a certain extent this is a traditional static class based way of thinking of the problem.

In Javascript there is no function overloading because functions are not identified by their signature only by name. That is setPoint(x,y) and setPoint(x,y,z) are references to the same function i.e. setPoint.

What this means is that to override a method inherited from the prototype object you simply redefine it. This looks a lot like what happens in a class based language but notice that the new function simply has to have the same name and not the same number of parameters.

For example if you write:

function Point3D()
{
this.z=0;
this.setPoint = function(x, y, z){
  this.x = x;
  this.y = y;    
  this.z = z;                          
};
}

then there is no way you can access the original inherited setPoint function only the new three parameter version. Of course in this case just making the z parameter optional would recover the same functionality but this isn't usually the case.

If you really need access to the base object's function then you have to store a reference to the prototype object in a suitably named property.

For example:

function Point3D()
{
this.base=Point3D.prototype;
this.z=0;
this.setPoint = function(x, y, z){
  this.x = x;
  this.y = y;    
  this.z = z;        
 }          
};

With this definition

point.setPoint(1,2);

calls the new Point3D method and

point.base.setPoint(1,2);

calls the original Point2D method. Of course you could simply use

Point2D.prototype.setPoint(1,2);

to call the base method without having to modify the 3D object.


Banner

<ASIN:0596805527>

<ASIN:0470684143>

<ASIN:0137054890>



Last Updated ( Monday, 18 October 2010 )