Skip navigation.
Home

Illumination on JavaScript Prototypes

Illumination on JavaScript Prototypes

You don't have JavaScript enabled. If you wish to run the JavaScript example code, you will need to enable JavaScript and refresh the page.



I saw a video the other day about how to implement classes in JavaScript. I thought the video was awesome, but it left me feeling that if you didn't already understand what he was talking about, you wouldn't have understood what he was talking about. So I have written this article to demonstrate how prototypes can be used to emulate class inheritance in JavaScript. I didn't keep the link, but I think it is one of Douglas Crockford's JavaScript videos.

One of the pages of Cassianus Corvina
A Hungarian illuminated manuscript from 1498 (Illumination on parchment)

Prototypes Are Easy

Prototypes are used to simulate class heirachies in JavaScript*. So if you want to use classes in JavaScript, you need to understand how prototypes work.

Fortunately once you understand a few key points, prototypes in JavaScript do actually make sense!

I found that when I first looked at examples of using JavaScript prototypes, the code just didn't make sense to me. It was a long period of time I finally worked out my fundamental misunderstandings. So in this article I have tried to explain prototypes clearly, with the goal of helping others from having the same misunderstandings.

* Although prototypes may have other uses, they are mostly used for implementing classes.

Prerequisites

There are a few things about JavaScript it helps if you know before getting started:

  • You should have a working knowledge of JavaScript syntax.
  • You should understand that objects in JavaScript are like objects in other scripting languages, and not at all like objects in a strongly typed language like C or C#. An object in JavaScript is similar to a hash or a dictionary - you can add extra properties to an object at any time.
  • I would help if you understand how in JavaScript methods on an object are actually just normal properties - properties that contain a reference to a function.
  • It would help if you understand that in JavaScript functions can be used like objects (e.g. setting properties on a function).

However, I have tried to write the article so that the above concepts are also explained where relevant, because sometimes the concepts are not obvious or well known to to many programmers; especially if you have only had experience of normal imperative languages and who are new to JavaScript.

Prototype Concept

Root class
Derived sub-class
Leaf sub-sub-class

Lets say we want to implement the above classes. JavaScript has no inbuilt* concept of classes. To implement this we create a single object for each class. For example, if three leaf objects were created, you would have the following objects:

* the latest versions of JavaScript do support classes directly, but if you want your scripts to work cross-browser with installed browsers, then you can't use the latest syntax.

Root prototype object
Derived prototype object
Leaf prototype object
Leaf object 1
Leaf object 2
Leaf object 3

In the diagram above, each arrow represents a hidden internal reference from each object to its prototypical parent object. All JavaScript objects have a hidden internal property that links upwards to the object's prototype. This reference is called the object's prototype.

The functioning of the prototype is straightforward: whenever code accesses a property on an object, if the property does not exist on the object, then the property is looked for on the prototype. The search for the property continues up the chain of prototypes until the property is found. If it is not found then undefined is returned as the value.

Prototype Demonstration

 some properties with values, and then have a play with the following to demonstrate how JavaScript prototypes work:

You don't have JavaScript enabled. None of these examples will work.

Root prototype object
property
value to
function
Derived prototype object
property
value to
function
Leaf prototype object
property
value to
function
Leaf object 1
property
value to
function
property
function
Leaf object 2
property
value to
function
property
function
Leaf object 3
property
value to
function
property
function

The above example is just for properties, but the above so that you can add and call functions too, and you can see how it works for functions. You might want to refresh the page first if you created lots of properties!

I hope the above demonstrates how prototypes actually work. Fortunately the actual concept of prototypes is pretty easy to understand (even just by reading other articles about prototypes - even if the specifics of how they are implemented is not so clear!).

Prototype Madness

Background: Functions are Objects

In JavaScript a function is actually just an object with special behaviour if used as a call - the () operator. This may be hard to understand if you are used to a normal imperative language. For example (nothing to do with prototypes):

function someFunction1() { alert('You called 1?'); }; someFunction1.prop1 = 666; someFunction1.prop2 = "Hiya!"; function testA() { alert( someFunction1.prop1 ); alert( someFunction1.prop2 ); } function testB() { someFunction1(); }

The following is the same as the above (for someFunction1), but it uses a variable set to an anonymous function. It sets the variable someVar2 to be a reference to the anonymous function function() { alert('You called 2?'); } declared after the = sign. It is an anonymous function because it doesn't have a name (someVar2 is a variable, not the name of the function). In some languages (and in academic articles) anonymous functions are called lambdas.

var someVar2 = function() { alert('You called 2?'); }; someVar2.prop2 = 'holy cow batman'; function testC() { alert( someVar2.prop2 ); } function testD() { someVar2(); }

The Prototype Reference is Hidden

Every JavaScript object has a hidden prototype reference.

What seems insane is that you can't find out what the prototype reference is [I hope that this statement is wrong - if right then that's braindead], and you can't directly initialise it, and you can never change it.

Some JavaScript implementations allow you to read the prototype using a property called __proto__.

Setting the Prototype Reference

OK, this part is the spooky part. The following code makes a newDescendent object that has a prototype of rootProto:

var rootProto = new Object(); rootProto.prop_x = 555; rootProto.fn_y = function() {alert('fn_y called');}; function constructorFn() { }; constructorFn.prototype = rootProto; // kooky var newDescendent = new constructorFn(); function test1() { alert( newDescendent.prop_x ); } function test2() { newDescendent.fn_y(); }

Note that there is nothing special about the prototype property set on a constructor function - it is just like any other property which you may set on a normal function object.

Constructor Functions

It is critical to realise that the only way you can set the hidden prototype reference in JavaScript is to use the new operator.

A constructor function is a normal function that you have called using the new operator. Usually the function will have a prototype property set on it.

Only when you use the new keyword in conjunction with the function does the prototype property get used in a special way. The prototype property of the function gets used by new to initialise the hidden prototype reference on the new object. So the prototype property should be set to the parent object you want your new objects to use for their prototype link. For example:

var baseProto = { prop_x: 888, fn_u: function() { alert('fn_u declared in baseProto'); }, fn_v: function() { alert('fn_v declared in baseProto'); } }; // Much the same as the rootProto example previously but using inline object creation function constructorFn8() { // This time lets do some initialization within the constructor function //'this' is initialised by new to the new object that was just made. alert('in constructorFn8 ' + this.prop_x); this.fn_v = function() { alert('fn_v declared in constructorFn8'); }; }; constructorFn8.prototype = baseProto; function test8() { // new creates the object and sets the prototype. // then constructorFn8 is called and it can set up properties on the new object. var x = new constructorFn8(); x.fn_u = function() { alert('fn_u declared in test8'); }; alert('after construction'); x.fn_u(); x.fn_v(); baseProto.fn_u(); }

The above also shows that a constructor function is much the same as a constructor function in many other languages.

Below demonstrates that you may have multiple constructor functions that use the same prototype — constructorFn9 is using the same prototype as constructorFn8.

function constructorFn9() { }; constructorFn9.prototype = baseProto; function test9() { var x = new constructorFn9(); alert('after construction'); x.fn_u(); }

Dynamic Prototype Modification

The objects you use for your prototypes are just normal objects. If you modify them then the changes are immediately visible in any other objects that were constructed with that prototype object. So using the prototype object baseProto by calling the constructor constructorFn9 from the previous example:

// set up dynam with a hidden prototype pointer to baseProto var dynam = new constructorFn9(); function testadd() { baseProto.testfn = function() { alert('testfn exists!'); }; } function testdel() { delete baseProto.testfn; } function testcall() { if (dynam.testfn) { dynam.testfn(); } else { alert('testfn doesnt exist on dynam'); } }

Classes and Subclasses

The above example code only shows how a single class is implemented. Simulating a class heirachy is exactly the same - however it looks complex because of the hoops you have to go through to get the hidden prototype references set correctly.

var theBasePrototype = new Object(); theBasePrototype.baseFunction = function() { alert('baseFunction'); }; function baseConstructor() {}; baseConstructor.prototype = theBasePrototype; // theMiddlePrototype needs to *already* have its hidden prototype pointer // set up. You can *only* do that by calling new baseConstructor() var theMiddlePrototype = new baseConstructor(); theMiddlePrototype.middleFunction = function() { alert('middleFunction'); }; function middleConstructor() {}; middleConstructor.prototype = theMiddlePrototype; // thefinalPrototype needs to have its hidden prototype reference to theMiddlePrototype // set up before it can be used in a constructor. var thefinalPrototype = new middleConstructor(); thefinalPrototype.finalFunction = function() { alert('finalFunction'); }; function finalConstructor() {}; finalConstructor.prototype = thefinalPrototype; function testfinal() { var obj = new finalConstructor(); obj.baseFunction(); obj.middleFunction(); obj.finalFunction(); }

An alternative scheme shown below uses the constructor functions to initialize the prototype objects. This style is used by many people and has much the same result (although there are subtle differences).

function baseConstructor2() { this.baseFunction = function() { alert('baseFunction'); }; }; // no prototype - base functions set up in constructor var theBasePrototype2 = new baseConstructor2(); function middleConstructor2() { this.middleFunction = function() { alert('middleFunction'); }; }; middleConstructor2.prototype = theBasePrototype2; var theMiddlePrototype2 = new middleConstructor2(); function finalConstructor2() { this.finalFunction = function() { alert('finalFunction'); }; }; finalConstructor2.prototype = theMiddlePrototype2; var theFinalPrototype2 = new finalConstructor2(); function finalObjectConstructor() {}; finalObjectConstructor.prototype = theFinalPrototype2; function testfinal2() { var obj = new finalObjectConstructor(); obj.baseFunction(); obj.middleFunction(); obj.finalFunction(); }

Class Emulation Lacks Normal Features

Using prototypes to emulate classes is not perfect and some normal things you expect classes to do are missing or odd, because they cannot be emulated easily. Most notable it is difficult to implement method overriding. In other languages you use the base or super or inherited keyword (amongst others) to call an overridden method. It is complex problem to try and solve in JavaScript and every solution has its caveats, so I am not going to discuss it. There are plenty of different solutions you can find with different compromises.

Another oddity is that emulated classes in JavaScript are actually made up of multiple objects, and the same property can exist on the different objects. This is hard to explain, but it is clear if you use the Prototype demonstration above and set up the same property at different levels in the heirachy.

Breviarium
National Sz'ch'nyi Library, Budapest (1480s, Tempera and gold on parchment, 302 x 225 mm)

Summary

Main points:

  • All JavaScript objects have a hidden reference to their parent prototype object.
  • The only way to set the hidden prototype reference is to use the new keyword in conjuntion with a constructor function.
  • A constructor function is just a normal function, with a property called prototype set to the parent prototype object you want to use.

Thank You

The article hasn't been up for long so any comments would be welcome. I am happy for you to email me, or you can leave a comment below (although note that I don't check comments particularly often). I especially want to know about any mistakes.
If you have any significant improvements then send me your edits to the HTML page! When the changes are posted up, I'll give you some cred (get your name on teh intarweb!) and I am happy to share some link love.

Thanks for reading!

Morris Johns





Appendix: A Variety of Remarks

Because there is no standard way to implement classes, every library, and every article, implements classes in their own quirky manner. This makes it difficult to understand other people's code. This section contains a few random notes about some code you may see in the wild.

function BaseClass() { /* empty function */ }; BaseClass.prototype.getName = function() { return "**BaseClass.getName()**"; } var x = new BaseClass(); alert(x.getName());

Every function has a default prototype property that is an empty Object. The above code adds a getName property to that prototype (the second line above doesn't need to initialise the BaseClass.prototype property).

function BaseClass() { /* empty function */ }; function DerivedClass() { /* empty function */ }; DerivedClass.prototype = new BaseClass(); var x = new DerivedClass(); x.prototype = DerivedClass.prototype; //x.prototype is nothing special

It is often useful to keep a reference to the prototype used to construct an object. In JavaScript prototype is not a reserved word so some people use a property called prototype to hold that reference (see last line in above).

function BaseClass() { this.func1 = function() { alert('**func1**'); }; this.func2 = function() { alert('**func2**'); }; }; var x1 = new BaseClass(); var x2 = new BaseClass(); x2.func1 = function() { alert('**FUNC1**'); }; x1.func1(); x2.func1();

Many people set up functions within the constructor function. The properties set up this way are not shared between objects created using the BaseClass constructor. The above code shows two alerts, "**func1**" followed by "**FUNC1**". However if you use one of the new objects as the prototype for a different constructor then they will be shared by descendents.

function BaseClass() {}; BaseClass.prototype.func1 = function() { // Could also write BaseClass.prototype['func1'] = function() { alert('**BaseClass.func1**'); }; function DerivedClass() { /* empty function */ }; DerivedClass.prototype = new BaseClass(); DerivedClass.prototype.func1 = function() { alert('**DerivedClass.func1**'); BaseClass.prototype.func1.apply(this, arguments); // call super }; var x = new DerivedClass(); x.func1();

Code like the line BaseClass.prototype.func1.apply(this, arguments); is often used to call a super/base function. The above code shows an alert "**DerivedClass.func1**" followed by "**BaseClass.func1**". You cannot just use BaseClass.prototype.func1() because then in BaseClass.func1 this would be set to the BaseClass.prototype object (this is quirky in JavaScript if you are used to traditional OO languages). Note that if you are unfamiliar with arguments, it is similar to @_ in perl or ... in C. arguments is an array of all parameters passed in with the function call, even if no parameters were declared by the function, or if there were less parameters declared than were passed in.

function declare_method(derivedClass, baseClass, methodName, method) { if (typeof baseClass.prototype[methodName] == 'function') { derivedClass.prototype[methodName] = function() { var previous = this.base; this.base = baseClass.prototype[methodName]; var returnValue = method.apply(this, arguments); this.base = previous; return returnValue; }; } else { derivedClass.prototype[methodName] = method; }; } declare_method(BaseClass, Object, "func2", function() { alert('**BaseClass.func2**'); }); declare_method(DerivedClass, BaseClass, "func2", function() { alert('**DerivedClass.func2**'); this.base(); // call super }); var x = new DerivedClass(); x.func2();

The above adds to the previous example and it demonstrates the technique used Dean Edward's base library to use this.base(arguments); to call a super method. Basically it adds a wrapper function around every function. Of course Dean's code is a bit smarter than that (it only adds the wrapper if the function contains the word base) also it looks like he has put it into a more comprehensive library called base2.

Douglas Crockford has yet another technique but I can't recommend looking at the code.


ECMA Appendix

A few snippets from the ECMA-262 ECMAScript Language Specification.

8.6.2 Internal Properties and Methods

Native ECMAScript objects have an internal property called [[Prototype]]. The value of this property is either null or an object and is used for implementing inheritance. Properties of the [[Prototype]] object are visible as properties of the child object for the purposes of get access, but not for put access.

4.2.1 Objects

ECMAScript does not contain proper classes such as those in C++, Smalltalk, or Java, but rather, supports constructors which create objects by executing code that allocates storage for the objects and initialises all or part of them by assigning initial values to their properties. All constructors are objects, but not all objects are constructors. Each constructor has a Prototype property that is used to implement prototype-based inheritance and shared properties. Objects are created by using constructors in new expressions; for example, new String("A String") creates a new String object. Invoking a constructor without using new has consequences that depend on the constructor. For example, String("A String") produces a primitive string, not an object.

ECMAScript supports prototype-based inheritance. Every constructor has an associated prototype, and every object created by that constructor has an implicit reference to the prototype (called the object's prototype) associated with its constructor. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.

In a class-based object-oriented language, in general, state is carried by instances, methods are carried by classes, and inheritance is only of structure and behaviour. In ECMAScript, the state and methods are carried by objects, and structure, behaviour, and state are all inherited. All objects that do not directly contain a particular property that their prototype contains share that property and its value. The following diagram illustrates this:

CF is a constructor (and also an object). Five objects have been created by using new expressions: cf1, cf2, cf3, cf4, and cf5. Each of these objects contains properties named q1 and q2. The dashed lines represent the implicit prototype relationship; so, for example, cf3's prototype is CFp. The constructor, CF, has two properties itself, named P1 and P2, which are not visible to CFp, cf1, cf2, cf3, cf4, or cf5. The property named CFP1 in CFp is shared by cf1, cf2, cf3, cf4, and cf5 (but not by CF), as are any properties found in CFp's implicit prototype chain that are not named q1, q2, or CFP1. Notice that there is no implicit prototype link between CF and CFp.

Unlike class-based object languages, properties can be added to objects dynamically by assigning values to them. That is, constructors are not required to name or assign values to all or any of the constructed object's properties. In the above diagram, one could add a new shared property for cf1, cf2, cf3, cf4, and cf5 by assigning a new value to the property in CFp.

Arrrrrgggghh - XSS detection

It seems my host provider has graciously implemented some XSS prevention code... which prevents me from posting script tags in my articles - aaaaaaaaaarrrrghh.

I wasted hours working this out (I finally caught on when they DoS'd my current IP address because they had decided I was a spambot - up till then I had thought it was a problem with Drupal!).
I ended up posting this article using phpMyAdmin ... madness!

Page is now static

Well, my hosting provider jatol.com kicked the bucket (they were cheap and I used them for years without problems - I don't have any axe to grind against them).

I am now using resellerzoom.com - 20 cpanel accounts for USD7 per month - seems like a good deal since I give family and friends website hosting and the techhead friends can access their own cpanel :)

Hopefully they stick around longer than jatol though...

(Of course this comment was written directly into the HTML - ha!)