Prototypes in JavaScript

This article was originally published in VSJ, which is now part of Developer Fusion.

One of the most misunderstood aspects of JavaScript is its status as an object-oriented language. Given the range of possible approaches to objects, and the equally wide range of strongly held beliefs about which is the one and only true way you, can tell that it’s a topic that can run and run. However there are issues that go to the practical use of the language, and of these the statement that “JavaScript is a prototype-based” language is perhaps the most important.

Many books perpetuate the myth that this is something mysterious to do with the Prototype property (see later). However the truth is the other way round – JavaScript is a prototype-based language and this makes it really useful to have a Prototype property. Let’s examine what this talk about prototyping is all about.

There are two very general approaches to creating objects. You can go about it indirectly and create a “class” from which you instantiate as many objects as you need. The class acts as a sort of tool that can be used to stamp out copies of the object. Many beginners find this difficult because they are focused on producing something that “does something” rather than working one stage removed – class then object. A prototype language on the other hand doesn’t bother with classes at all – it’s class free. What happens is that the programmer creates objects by writing the code that implements a single object. Beginners tend to like this as it is direct – you want an object so you write the code for the object, no mucking about with classes that simply get in the way and cause problems with thinking up names. For example, if you need a stack object in a class-based language you first have to implement a class called CStack and then create an instance of a stack object something like:

CStack Stack = new CStack()

In a prototype language you don’t have to invent CStack – simply write the code that is within CStack as if it was the Stack object.

This is the approach that JavaScript takes, but it isn’t the first language to do so – in fact Visual Basic 6 also took the prototype approach to creating forms. In this case you simply coded an object called Form1 and used it. In .NET you have to code a class and then instantiate it.

Of course creating a single instance of an object doesn’t really give you the full benefit of an object-oriented approach, but prototype languages solve this by providing the ability to clone objects. Instead of stamping out identical objects using a class you simply create more objects by cloning existing objects. Once you have the cloned object you can change its behaviour by adding methods and properties to it. In fact most prototype languages don’t bother providing a facility to create a new object, they simply provide some built-in objects that you can clone to create your own objects. So to be clear:

  • a prototype-based language doesn’t have classes
  • instead you create objects by cloning and modification

JavaScript is a prototype-based language… and almost everything is an object.

New and construction

The way that JavaScript creates objects is very confusing, all the more so for the additional ways that people have found to make it look more like a class-based system. JavaScript objects are all derived from the built-in Object. Every object has a constructor function which has the same name as the object and is generally called using the new operator. For example, to create a new object you would use:

obj1 = new Object();

At this juncture you might want to point out that this isn’t the way you usually create an object. It is true that JavaScript has many ways of expressing the same idea but this is its essence. Notice that in this case Object is not the built-in object but a constructor function object of the same name. The action of the instruction is to leave obj1 referencing a new copy of the built-in Object. You can add methods and properties to an object simply by assignment. So for example:

Object.temp1 = 1;

…adds the temp1 property to the built-in object. Notice that this new property isn’t replicated when you create a new object. That is obj1 doesn’t have a temp1 property even though Object does. The reason for this is that the properties that a created object has are determined by the associated constructor function and not the object. That is, you may have changed Object but you haven’t changed Object().

If you don’t get any of the customisations passed on when you create an object from an existing object there doesn’t seem to be much point to it all. It looks as if every object has to be started as if it was a blank canvas. This isn’t quite true. The Object() constructor makes sure that every new object comes with a set of standard properties and methods. You can look up the full list, but from the point of basic object construction the one that is most important is “constructor”. This is a reference to the object’s constructor function and this can be used along with the new operator to create another object. For example:

obj1 = new Object();
obj2 = new obj1.constructor();

This creates a new object obj2 from obj1 but again obj2 isn’t given any of the custom properties that obj1 might have. That is, after:

obj1 = new Object();
obj1.temp1 = 1;
obj2 = new obj1.constructor();

obj2 doesn’t have a temp1 property. The reason is that obj1’s constructor is still Object() and so obj2 is just another example of the built-in Object. We don’t seem to be getting anywhere!

The solution to the problem is quite subtle. The constructor that obj1 acquires is a reference to a copy of the Object’s constructor. Add to this the fact that the constructor object function also has a standard object property called prototype and we can start to see how objects can pass on properties. If you think that the following code looks a little strange then it is worth mentioning that objects that are Functions have prototype properties, and this accounts for the many alternative ways of writing JavaScript object-oriented code.

Let’s try an example. First we construct a new object and add a new property to its constructor’s prototype property:

obj1 = new Object();
obj1.constructor.prototype.temp1 = 1;

This also has the effect of adding the property to obj1 because JavaScript uses the rule that if it can’t find a property defined directly within the object it then looks for it in the constructor’s prototype object. So following this we can write:

alert(obj1.temp1)

…and the property will be found and the value 1 printed. That is, the above property reference is the same as:

alert(obj1.constructor.prototype.temp1);

…but notice that if you define a property of the same name directly:

obj1 = new Object();
obj1.constructor.prototype.temp1 = 1;
obj1.temp1 = 2;
alert(obj1.temp1);
alert(obj1.constructor.prototype.temp1);

…then the two temp1 properties are different. Only if there is no property of the same name is the constructor’s prototype object property used. Now if you create a new object based on obj1:

obj2 = new obj1.constructor();
alert(obj2.temp1);

…it follows the same rules – if it can’t find temp1 among its properties it looks in its constructor’s prototype object. The complication is that this, obj2’s constructor’s prototype object, is a reference to obj1’s constructor’s prototype object. What this means is that obj1.temp1, obj2.temp1, obj1.constructor.prototype.temp1 and obj2.constructor.prototype.temp1 are all the same variable. In other words, variables defined on the prototype object are shared by all objects created from the “base” class – obj1 in this case. You should be able to see that this also implies that adding a new property to any of the object’s constructor’s prototypes adds it to all of the objects. For example, if you create a third object and add a prototype property temp2 to it then all of the objects now have a temp2 property. That is, after:

obj1 = new Object();
obj1.constructor.prototype.temp1 = 1;
obj2 = new obj1.constructor();
obj3 = new obj2.constructor();
obj3.constructor.prototype.temp2 = 2

alert(obj1.temp2);
alert(obj2.temp2);
alert(obj3.temp2);

temp2 exists in all objects and its value is 2. Notice that if you try to assign to any prototype properties as if they belonged to the object, then a new and distinct object property is created which masks the prototype property. That is, if you finish the previous example with:

obj3.temp2 = 3;
alert(obj1.temp2);
alert(obj2.temp2);
alert(obj3.temp2);

…then obj1.temp2 and obj2.temp2 are still prototype properties but obj3.temp2 belongs only to obj3 and has the value 3.

This still isn’t of much use in creating clones of objects. What we have so far is the ability to build individual objects that “inherit” a core functionality implemented as “static” methods and properties. Currently we have no way to create an object that inherits instance methods and properties from an existing object. The solution to this problem is to create objects from custom constructor functions. Instead of creating objects from the Object() constructor we can make our own constructor. For example:

obj1 = new Function()
{
    temp = 1;
}

Now we are using a constructor created “on the fly” which creates a new property “temp”. However if you try to make use of temp you will discover that instead of creating obj1.temp we have created a global temp variable not tied to an object. You could change the definition to:

obj1 = new Function()
{
    obj1.temp = 1;
}

…and this does create a property for obj1 but if you use it to construct obj2, say, then you still define a property for obj1. The solution is to use “this”, which is always set to the current object involved in the operation. So:

obj1= new function()
{
    this.temp = 1;
};

…creates a new object called obj1 with a constructor given by the function and a new property obj1.temp, set to 1. Following this you can write:

obj2 = new obj1.constructor();

…and this constructs a new object called obj2, with its constructor referencing the constructor for obj1 but with a new property obj2.temp which is also set to 1 but has nothing more to do with obj1’s temp property after construction.

It has to be said that this isn’t the usual way of working with JavaScript objects but it is the closest to the prototype approach and well worth understanding.


Ian Elliot is a development programmer with I/O Workshops Ltd, a consultancy which solves real world problems for clients with widely varying requirements.

You might also like...

Comments

About the author

Ian Elliot United Kingdom

Ian Elliot is a development programmer with I/O Workshops Ltd, a consultancy which solves real-world problems for clients with widely varying requirements.

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Programs must be written for people to read, and only incidentally for machines to execute.”