JavaScript Inheritance by Example

As Douglas Crockford already pointed out, JavaScript is a class-free, object-oriented language, and uses prototypal inheritance instead of classical inheritance. But what does that actually mean and how does it work in a real example?

Learning by doing

Lets take the following example where we would like to create a constructor function for an object “Vehicle” and then create another function “Car” which should inherit properties from “Vehicle”. We proceed through the following steps:

  1. Create constructor function for Vehicle
  2. Create constructor function Car
  3. Set up dynamic inheritance (this ensures that when you add a property to “Vehicle”, an instance of Car inherits that property)
  4. Extend Car using prototype
  5. Create a new instance of Car – my new Audi
  6. Extend Vehicle using prototype

Step 1: Create constructor function for Vehicle

The first step is very straight forward, what we would like to achieve is setting up the “blueprint” for a Vehicle object, so we define the constructor function like this:

function Vehicle(hasEngine, hasWheels) {
    this.hasEngine = hasEngine || false;
    this.hasWheels = hasWheels || false;
}

The logical OR operator makes sure that, if no values get passed into that contructor function, the properties hasEngine and hasWheels still have values assigned to them. So that was a piece of cake.

Step 2: Create constructor function Car

Now we would like to do a similar thing for Car. We want to pass in make, model and horsepower of the car and store that in the properties of the object. We do that like:

function Car (make, model, hp) {    
    this.hp = hp;
    this.make = make;
    this.model = model;
}

This is basically the same as above, nothing special. We would now create a new Car object by passing in make, model and hp using the new operator. But for now, Car and Vehicle do not have anything to do with each other at all.

Step 3: Set up dynamic inheritance

Now it is getting interesting. What we would like to achieve is to make Vehicle and Car relate to each other in some way. To be specific, Car should be able to inherit properties from Vehicle if we were to extend it (using prototype).

We do this by using the prototype property of Car, like so:

Car.prototype = new Vehicle(true, true);

What JavaScript does when it reaches that statement is the following:

  1. The new operator creates a generic object and assigns its __proto__ property to Vehicle.prototype
  2. The new operator passes the object to the Vehicle constructor function as the this keyword.
  3. The object gets the properties hasEngine and hasWheels assigned
  4. Upon return from the constructor, the object gets assigned to Car.prototype

What we have set up here is an inheritance chain from Vehicle to Car. The prototype property of Car now points to the abovementioned generic object, which consists of the following properties:

  • hasEngine
  • hasWheels
  • __proto__ (which points to Vehicle.prototype which is empty at this point)

We will make use of that construct in Step 6.

Step 4: Extending Car using prototype

We would like to extend the capabilities of Car by a function displaySpecs, which should log the details of the car to the console using console.log. We do this using prototype:

Car.prototype.displaySpecs = function () {
    console.log(this.make + ", " + this.model + ", " + this.hp + ", " + this.hasEngine + ", " + this.hasWheels);
}

We have extended the functionality of Car by adding another function to the abovementioned object which is referenced using prototype. That object now holds the following:

  • hasEngine
  • hasWheels
  • displaySpecs
  • __proto__ (which points to Vehicle.prototype which is still empty)

Step 5: Creating a new Car

Now we have set up the foundations in order to proceed with creating an instance of Car. Let us make it an Audi, just to be posh.

var myAudi = new Car ("Audi", "A4", 150);

We can go through it again step by step:

  1. The new operator creates a generic object and sets its __proto__ property to Car.prototype
  2. The new operator passes that object to the Car constructor function as the this keyword
  3. The object gets hp, make and model properties with the values passed in assigned
  4. Upon return from the constructor function, the object gets assigned to the myAudi variable

This means that the newly created instance of Car has the following properties:

  • hp: 150
  • make: “Audi”
  • model: “A4″
  • __proto__ (pointing to Car.prototype, which holds hasEngine, hasWheels and displaySpecs)

If we now call displaySpecs, it will output the properties of myAudi to the console:

myAudi.displaySpecs(); // logs: Audi, A4, 150, true, true

This works because of the way JavaScript looks for the availability for properties of objects:

  1. First, it checks whether displaySpecs is available in myAudi (which it is not)
  2. Next, it goes up the inheritance chain using __proto__ which points to Car.protoype
  3. Car.prototype holds displaySpecs, so the function gets executed in with the scope of myAudi. This means that within displaySpecs, the keyword this refers to myAudi object. Consequently, it prints out the properties of myAudi (“Audi”, “A4″ etc.)

Step 6: Extend Vehicle using prototype

Now you might decide that you would like to extend the original capabilities of Vehicle. Using prototype lets us do that, so if we would want, for some reason, to add a hasTrunk property, we can do that like so:

Vehicle.prototype.hasTrunk = true;

Because we have set up dynamic inheritance, this makes sure that the object we created, myAudi, inherits that property. If we were to output that property to the console, we will see that this has worked:

console.log(myAudi.hasTrunk); // logs: true

This is, again, due to the inheritance chain we have set up:

  1. Is hasTrunk available in myAudi itself: no
  2. Is hasTrunk available in Car.prototype: no
  3. Is hasTrunk available in Vehicle.prototype: yes

JavaScript has worked itself up the inheritance chain and then logs the value of hasTrunk to the console. If hasTrunk is not found, we would get “undefined” in the console.

Sidenote & Conclusion

If you would want to avoid passing in properties to the Vehicle constructor when setting up the inheritance chain, you can call the Vehicle constructor from within the Car constructor like so:

function Car (make, model, hp) {
    this.base = Vehicle;
    this.base(true, true);

    this.hp = hp;
    this.make = make;
    this.model = model;
}

and setting up dynamic inheritance like this:

Car.prototype = new Vehicle;

Now everytime a new Car instance gets created, the Vehicle constructor is invoked and hasEngine and hasWheels are set to true and set as properties of the newly created object. Details about that can be found at the Mozilla Developer Center.

To me, this little example made things a lot clearer and especially having some sort of visual image helps a lot of grasping what is going on and how inheritance within JavaScript works. In order to think through the example again, please have a look at the demo page (in Firefox with Firebug opened on the console tab) for this little example.

Resources

About the author

This website is the personal web appearance of Klaus Komenda, an Austrian web developer. The about section offers more info about me and this site.

Categories

Copyright © 2000-2014 Klaus Komenda