Prototypes in JavaScript

An in-depth look into Prototypes and Prototypal Inheritance in JavaScript.

Mastering prototypes and prototype-based inheritance is essential to understanding JavaScript. Here we will take a deep dive in exploring prototypes.



Essentials: a deep dive


No other feature of JavaScript has created as much confusion as prototypes. The area that seems to cause the most trouble is creating new object instances using constructor functions. Indeed, it is confusing if you consider that a constructor function object has a prototype and a constructor and the new object also has a prototype that gets assigned from the constructor function.

Mastering prototypes and prototype based inheritance is essential to understanding JavaScript. In this section, we suggest you forget everything you knew about prototypes and we will guide you step by step in building up solid foundation that you can use in your own projects. So here it goes.

What is a prototype?
A prototype is a regular object from which other objects inherit properties. Each object has an internal prototype property that points to a prototype object from which it inherits all members (properties and methods). Consider the following code:

var Car = function () { };

Car.prototype = { make: "Mercedes" };

var toyota = new Car();
var mercedes = new Car();

alert(toyota.make);             // => Mercedes
alert(mercedes.make);           // => Mercedes

Run

We have a Car constructor function and a prototype with a property called make with a default value Mercedes. Two car instances are created: toyota and mercedes. Their make property is shared and the value is Mercedes as expected. This is called prototypal inheritance.

Next we change the make value on toyota:

var Car = function () { };

Car.prototype = { make: "Mercedes" };

var toyota = new Car();
var mercedes = new Car();

toyota.make = "Toyota";

alert(toyota.make);             // => Toyota
alert(mercedes.make);           // => Mercedes

Run

It shows that make is Toyota for toyota and Mercedes for mercedes. To some developers this comes as a surprise. They expected the make value on the prototype to change, but that is not the case. JavaScript only follows the prototype chain when getting a value, not when setting a value. This is an important distinction. When setting a value and the property does not exist on the object itself, it simply creates the property. Now that toyota has a make property is shadows (or hides) the prototype value for make.

Let's get back to prototypes and the inheritance chain. What exactly are prototype objects? In fact, there is nothing special about prototype objects; any object that is not a primitive (number, string, Boolean, null, or undefined) can be a prototype object. Here is a diagram that shows the prototype chain for the above example:

toyota (instance) → Car.prototypeObject.prototype → undefined

The toyota object instance starts on the left. It points to the Car.prototype object in the middle. The prototype object itself is an object and therefore has its own prototype. This prototype is the default object, called Object.prototype, which is at the root of all inheritance chains. The default prototype itself does not have a prototype and is undefined.

Let's look at some simple code.

var document = {};

alert(document.prototype);      // => undefined

Run

Notice that the document.prototype is undefined. How is this possible? We just said that each object has a prototype and our very first object already doesn't have one? This is a major source of confusion. The reason is that the true prototype reference is an internal property called [[Prototype]] which is not directly accessible from your code.

[[Prototype]] and __proto__
To get to this internal property, ES5 (EcmaScript 5) offers a standard accessor method: Object.getPrototypeOf(object). This is available in all modern browsers. In addition, all browsers, except IE 9 and below, also offer a non-standard accessor named __proto__. If none of these work you can still get to the prototype object via the prototype property on the object's constructor. Let's explain all this with some code:

var document = {};

// ES5 (all modern browsers)
alert(Object.getPrototypeOf(document));  // => [object Object]

// not available in IE9 and below
alert(document.__proto__);               // => [object Object] 

// availabe in all browsers
alert(document.constructor.prototype);   // => [object Object] 

Run

This shows the three ways to get to the internal prototype property. By the way, the constructor property on the last line will be explained shortly. This code confirms that document indeed has a prototype object.

You may be wondering why there is no document.prototype property in the above example. The answer is that it is best to forget everything you knew about the prototype property. There are no properties named prototype, except in constructor functions. It's a little broader than that: only function objects have prototype properties, but no other objects.

The following is important: The prototype property of a constructor function is the prototype that will be assigned as the prototype to all newly created objects. Constructor functions have a prototype property, but it is only used to assign a prototype to a newly created object. A constructor function is an object itself, so it must have its own prototype, that is, [[Prototype]] or __proto__. This is correct, but don't confuse it with the one named prototype.

The code below demonstrates that the prototype property of a constructor function is a genuine object, unlike undefined as we saw before in our document object:

var Document = function () {};  // Constructor function

alert(Document.prototype);      // => [object Object]

Run

As we mentioned before, this prototype will be assigned as the prototype to all instances that are created by the constructor. These prototype objects can be customized with properties and methods, like so (you should already be familiar with this style of code):

var Document = function () {
    this.type = "unknown";
};

Document.prototype.say = function () {
    alert("Type: " + this.type);
};

var doc = new Document();
doc.type = "pdf";
doc.say();                     // => Type: pdf

Run

Alternatively, you can assign an object literal (frequently with multiple methods and properties) to a prototype:

var Document = function () {
    this.type = "unknown";
};

Document.prototype = {              // object literal
    say: function () {
        alert("Type: " + this.type);
    }
};

var doc = new Document();
doc.type = "pdf";
doc.say();                         // => Type: pdf

Run

Again, the prototype property has nothing do with the function's actual prototype. We will refer to an object's true prototype property as __proto__ which works in all browsers, except in IE. By the way, __proto__ will be standard in ES6 (EcmaScript 6). Here we confirm that __proto__ and 'prototype' are indeed different (be sure not to run this in IE):

var Employee = function () {
    this.name = "unknown";
};

alert(Employee.prototype == Employee.__proto__);       // => false
alert(Employee.__proto__ == Function.prototype);       // => true

Run

What is this Function.prototype on the last line? It is the default prototype object for all function objects. Similarly, the default prototype object for all objects is Object.prototype. Object.prototype is a root object of all objects in JavaScript.

Function.prototype is the prototype for all functions. Function.prototype's prototype is Object.prototype which we referred to as the root object before. Next we have a diagram that depicts these relationships for the following JavaScript code:

function Employee() { };

var object = new Object();
var employee = new Employee();

The orange ovals are object instances; the blue shapes are prototype objects, and the green boxes are function objects. In this diagram we only show the true prototype relationships, represented by the __proto__ properties (i.e. [[Prototype]] in ES5) that each object has.

At the top we have Object which is a built-in constructor function that creates objects. At the bottom we have a custom Employee constructor function that creates employee objects. In the middle we have an object instance that was created with new Object() and below that one an employee instance which was created with new Employee().

Function objects and object instances are objects meaning they should all have prototypes. You can confirm this in the diagram that this is indeed the case. All four (the two green and orange shapes) point to a blue prototype shape. The prototypes themselves are objects too and therefore they also have their own prototypes. Again you can confirm this in the diagram. The one exception is the root object (Object.prototype) which has a __proto__ value of undefined. Actually each browser is different: it is undefined in IE, function () {} in Firefox, and function Empty() {} in Chrome.

The prototype for all function objects (built-in and custom) is Function.prototype. The diagram shows that both functions (Object and Employee) have Function.prototype as their prototype. Function.prototype, in turn, has Object.prototype as its prototype.

The employee instance has as its prototype Employee.prototype which in turn has Object.prototype as its prototype. The instance named object just has Object.prototype as its prototype.

Our diagram shows a total of 4 prototype chains, all ending with the root object, i.e. Object.prototype. They are:

function Object       → Function.prototype   → Object.prototype
function Employee  → Function prototype   → Object.prototype
object instance       →                                       Object.prototype
employee instance  → Employee prototype → Object prototype


With the diagram at hand and a better understanding of the prototype chain let's run a few quick tests:

function Employee() { };

var object = new Object();
var employee = new Employee();

alert(Employee.__proto__ === Object.__proto__);                // => true
alert(object.__proto__   === Function.prototype.__proto__);    // => true
alert(Object.__proto__);          // => undefined or Empty() or function()

Run

This confirms what we see in the diagram. Again, the terminating __proto__ value, as shown in the last statement, may return a different value in different browsers.

So far we have only looked at the __proto__ properties which reference the true objects in the prototype chain. Next, we are going to introduce the prototype property which is the source of so much confusion. To re-iterate: the prototype property only exists on functions and constructor functions and they use this object as the prototype for all instances that it will create. Here it is in the diagram.

The prototype references are depicted as red dotted lines. We only have two functions so there are only two red prototype references. These are the prototypes of the objects that are created by the function which is easy to see in the diagram.

The function Object has a prototype of Object.prototype, which is indeed the __proto__ for the orange object instance. Likewise, the function Employee has a prototype of Employee.prototype which is the __proto__ for the orange employee instance.

Hopefully it is clear now that a function's 'prototype' is very different from '__proto__'. They serve totally different purposes. Let's confirm all the above with some code:

function Employee() { };

var object = new Object();
var employee = new Employee();

alert(object.__proto__ === Object.prototype);                // => true
alert(employee.__proto__ === Employee.prototype);            // => true

Run

Indeed, this confirms what we see in the diagram.

Constructor
Finally, there is the constructor property which we saw at the beginning of this section. This property sits on prototype objects that were created by constructor functions. It simply points back to the function that created it. Here is the diagram for it:

The constructor references are depicted as green dotted arrows. They emanate from prototype objects pointing to the function objects that created them. Notice that prototype and constructor references come in bi-directional pairs. The constructor function objects have a prototype reference to their prototype objects and the prototype objects have a constructor reference back to the function that created them. The constructor references help JavaScript in identifying the type of an instance, for example the instanceof operator (see below). It allows the employee object to determine that it is an Employee.

We can run some confirmation tests:

function Employee() { };

var object = new Object();
var employee = new Employee();

alert(object.constructor === Object);                // => true
alert(employee.constructor === Employee);            // => true

alert(employee.__proto__ === Employee.prototype);    // => true
alert(Employee.prototype.constructor === Employee);  // => true
alert(employee instanceof Employee);                 // => true

Run

If you look carefully at the previous diagram you may see that something is missing. We mentioned that prototype objects have a constructor property, but the built-in Function.prototype does not appear to have one. In reality it does: there is a built-in function called Function. Here is the complete picture:

The function named Function (at the bottom of the diagram) is the constructor function for Function.prototype. Here is another test:

function Employee() { };

var object = new Object();
var employee = new Employee();

alert(Function.prototype.constructor === Function);     // => true
alert(Function.constructor === Function);               // => true

Run

This is kind of interesting: Function is its own constructor! Furthermore, you may recognize that the last two statements are exactly the same. The only difference is that with the last statement JavaScript has to do a little more work in finding out that constructor is not a property on Function itself, but on its prototype.

Let's recap what we have seen so far. Each object has a prototype from which it inherits properties and methods. An internal property named [[Prototype]] references the prototype. In all browsers, except IE, this property is called __proto__ and this is how we referred to it in our discussion. Only function objects have a property named prototype; no other object has this. Constructor functions use the prototype property to assign prototypes to newly created objects.