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?
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:
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.
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.
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:
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:
We will make use of that construct in Step 6.
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:
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:
This means that the newly created instance of Car has the following properties:
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:
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:
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.
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 for this little example.
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.