Javascript prototype chaining

Prototype chaining is used to build new types of objects based on existing ones. It has a very similar job to inheritance in a class based language.

Constructor functions have a property called prototype. Adding properties and methods to the prototype property will automatically add the method or property to all objects created by the constructor function.

Prototype chaining is an extension of this idea. The prototype property is just a regular javascript object so it’s possible to create a function’s prototype using another constructor function. When you do this, all of the properties and methods from the constructor function’s prototype are automatically added to new the prototype object. This makes it easy to create a constructor function that builds objects that are an extended version of an existing one.

For a simple example, imagine that you have a Pet constructor to make pet objects. Now you want to make Cat that is pretty much like a Pet but has a few differences.

Here’s the Pet constructor function from the prototype example:

  1. function Pet(name, species, hello)
  2. {
  3.     this.name = name;
  4.     this.species = species;
  5.     this.hello = hello;
  6. }
  7.  
  8. Pet.prototype = {
  9.     sayHello : function()
  10.     {
  11.         alert(this.hello);
  12.     }
  13. }

We can give the cat all the properties of the Pet by setting it’s prototype to be a new pet object:

  1. function Cat(name, hello, breed, whiskerLength)
  2. {
  3.     this.name = name;
  4.     this.species = species;
  5.     this.hello = hello;
  6.     this.breed = breed;
  7.     this.whiskerLength = whiskerLength;
  8. }
  9.  
  10. Cat.prototype = new Pet();
  11. var rufus = new Cat("rufus", "miaow", "Maine Coon", 7);
  12. rufus.sayHello();

This is not really any different to creating the prototype using object literal syntax. The only big difference is that instead of manually adding the methods to the object literal, the Pet’s prototype does most that work for us.

We can still extend the Cat objects by adding extra methods to the prototype. Any methods added to the cat prototype will only be available to objects created by the Cat constructor. Objects created by the Pet constructor will still only have the methods added directly to Pet:

  1. Cat.prototype.catNap = function()
  2. {
  3.     alert(this.name + ": zzzzz…");
  4. }
  5. rufus.catNap();

We can override any methods that came from the Pet constructor just by creating a new version of the function and assigning it to the Cat prototype. This will give cats different behaviour to the other pets:

  1. Cat.prototype.sayHello = function()
  2. {
  3.     alert(this.hello + " from a cat..");
  4. }
  5. rufus.sayHello();

Complete example

Function resolution

The most important thing to understand when using prototype chaining is how the method resolution works. Method resolution is what happens when you call a method or property on an object. It’s how javascript figures out what method or property should really be called.

First javascript checks the object itself for the method. This is important because it means you can override any method from the prototype on any object. If we call rufus.avoidPhoto() in the following example, javascript will call the avoidPhoto() function that has been assigned directly to rufus:

  1. var rufus = new Cat("rufus", "miaow", "Maine Coon", 7);
  2. rufus.avoidPhoto = function()
  3. {
  4.     alert("Talk to my agent. ");
  5. }
  6. rufus.avoidPhoto();

If the object doesn’t have the method set directly on it, javascript then looks for a Constructor function that created the object. Javascript checks the constructor’s prototype property for the method. If we call rufus.catNap(), javascript will find the method on Cat.prototype and use it:

  1. Cat.prototype.catNap = function()
  2. {
  3.     alert(this.name + ": zzzzz…");
  4. }
  5.  
  6. var rufus = new Cat("rufus", "miaow", "Maine Coon", 7);
  7. rufus.catNap();

If the constructor function’s prototype doesn’t have the method defined, javascript looks at what constructor function was used to create the prototype property and does the same thing again. It will keep walking the prototype chain until it finds a function that matches. If rufus.eat() is called in the following example, javascript will walk up the prototype chain until it gets to the Pet constructor’s prototype object and then use Pet’s eat() method:

  1. Pet.prototype = {
  2.     …
  3.     eat : function()
  4.     {
  5.         alert("nom! nom! nom!");
  6.     }
  7. }
  8.  
  9. Cat.prototype = new Pet();
  10. ..
  11. var rufus = new Cat("rufus", "miaow", "Maine Coon", 7);
  12. rufus.eat();

All objects ultimately have the Object constructor at the end of their prototype chain. This means any methods or properties added to the Object property are automatically available to all objects. Javascript libraries often use this to extend the javascript API.

In the previous example, if we called rufus.toString(), javascript would check the rufus object, then the Cat object, then the Pet object. The Pet object’s prototype was created with the Object constructor (using the object literal shortcut) so javascript would then find the toString() method on the Object’s prototype.

Walking the prototype chain

In theory it’s possible to walk the prototype chain using an object’s constructor property. Each object has a property called constructor that holds a reference to the constructor method that created it. The constructor’s prototype property is just a regular object, so it also has a constructor property that points to the next constructor function in the chain:

  1. var rufus = new Cat("Rufus", "miaow", "maine coon", 12);
  2. alert(rufus.constructor);
  3. alert(rufus.constructor.prototype.constructor);

Complete example

In theory the first alert statement will show the Cat constructor and the second will show the Pet constructor. In practise they both show the Pet constructor. This makes sense when you think about the prototype chaining behaviour. When you create the Cat’s prototype object, it’s constructor property will get set to Pet because it was created by the Pet constructor. When you look at the constructor property of the rufus object, rufus doesn’t have a value set explicitly on it so it looks for it on the Cat’s prototype object where it is set to Pet.

To fix the problem, you just need to set the constructor property explicitly on the object itself when you create it:

  1. function Cat(name, hello, breed, whiskerLength)
  2. {
  3.     Pet.call(this, name, "cat", hello);
  4.     this.breed = breed;
  5.     this.whiskerLength = whiskerLength;
  6.  
  7.     // needed because otherwise it will inherit the constructor
  8.     // from pet
  9.     this.constructor = Cat;
  10. }

Complete example

In mozilla based browsers each object exposes another property called __proto__ that gives you access to the way that the browser tracks the prototype chaining. The __proto__ property is a reference to the prototype property of an object’s constructor from the object itself:

  1. alert(rufus.__proto__ == Cat.prototype);
  2. alert(rufus.__proto__.__proto__ == Pet.prototype);

Complete example

This property is not supported across all browsers, so it’s not very useful when writing code but it can be very useful when debugging because it lets you take a peak at what the browser is actually doing.

If you come from a class based language you might be tempted to use the prototype chain to figure out what type an object is. The properties and methods of a javascript object can be modified after the object is created, so knowing about the constructor is no guarantee that the object will conform to a particular interface. You may choose to make your code work this way by convention but it’s important to remember that it is not enforced by the language itself.

I think it’s also worth considering that this is not really the javascript way of doing things. In javascript you don’t get static types, instead you use duck typing to ask an object what it can do. It’s important to use javascript’s strengths as a dynamic language with features like first class functions, closures and anonymous functions to write concise and modular code rather than trying to make it act like a different type of language.

What’s next?

In languages like C# and Java you never really need to give a thought to the this operator. In javascript things are a little more complicated due to functions being first class objects. The next article talks about javascript method context.

This article is part of a set of related posts about How javascript objects work.

Posted on 17 Aug 09 by Helen Emerson (last updated on 29 Nov 09).
Filed under Javascript