Classing in ES5

June 16, 2016

Creating classes and using inheritance chains are fundamental to object-oriented programming. For a more detailed explanation of OOP in JavaScript, I recommend the following resource on the Mozilla Developer Network. In this post, we will explore how to create a class/superclass, a subclass, and use a superclass method within a subclass instance.

For this post, I am going to use the following definitions of superclass and subclass. A superclass is one from which a subclass inherits certain properties and methods. A subclass will delegate failed property lookups to the superclass.

Let’s imagine a very simple racing game that has two types of vehicles: Cars and Vans. A Van is a type of Car with a couple different properties. We can say that the Van is a subclass of the Car superclass. For now, we will create the Car constructor function following the pseudoclassical pattern.

The Car will take a starting location value as an argument. The Car also has a move method that increases the value of its location by two.

function Car (loc) { this.loc = loc; } // Cars can move two spaces at a time Car.prototype.move = function () { this.loc += 2; console.log(this.loc); }; // Cars can rev engines Car.prototype.rev = function () { console.log(‘vrooom’); };

A Van is like a Car in that it takes a location value as an argument. Therefore, the Car constructor is be called within the context of the Van constructor passing in the loc parameter. The Van also has a boost property set at 2. The inheritance chain is then created and the constructor property set to refer to the correct constructor function.

function Van(loc) { Car.call(this, loc); this.boosts = 2; } // Set up inheritance chain Van.prototype = Object.create(Car.prototype); // Set constructor property to refer to correct constructor function Van.prototype.constructor = Van;

One difference between the Van and Car is that the Van only moves 1 space at a time. That is to say, the move method on the Van increases its location value by 1 each time.

// Vans can only move one space at time Van.prototype.move = function () { this.loc += 1; console.log(this.loc); };

Notice here that Van.prototype.move places the move method on the prototype of any Van instance. Therefore, any calls for newVan.move() check the Van.prototype and stop there. The lookup does not need to go to the Car.prototype for the move method. Compare this to calling newVan.rev(). The Van.prototype does not have the rev method and must delegate its failed lookups to the Car.prototype which possesses the method.

However, the Van has an added feature of a nitro method. When nitro is called, the Van is propelled forward at a faster speed and the value of boost is decremented by one. The nitro method counts as only one move, but the Van moves as fast as the Car and runs twice. See below.

// Vans also come with a nitro feature that lets it move // at the same speed as the car and runs twice Van.prototype.nitro = function () { console.log('activating nitro'); this.boost -= 1; Car.prototype.move.call(this); Car.prototype.move.call(this); console.log('new location of the van: ', this.loc); console.log(‘boosts remaining: ‘, this.boosts); };

While it would be possible to use the Van.prototype.move method here, this practice would not be advisable. Currently, four invocations of Van.prototype.move result in the same movement as two invocations of Car.prototype.move. In the future, we may revise the move method of the Car to increase the loc by 3. In that case, we would have to remember to change the Van.prototype.nitro method as well.

Instead, we can invoke the superclass method, Car.prototype.move, within the context of the subclass using call. The call method on the Function object allows the context of a function to be changed. In the nitro method, the this inside call is referring to the Van constructor. If we decide to change the move method of the Car, the nitro method will automatically include those changes.

Prior to the the 2015 update, JavaScript did not have an explicit means to create classes and subclasses. In order to mimic other programming languages with classing methods, the pseudoclassical instantiation method is used. In the 2015 updated, the class keyword was introduced, abstracting away some of the complexity of the ES5 prototype-inheritance pattern. In a future post, classing and subclassing will be explored using ES2015 syntax.