Object Oriented Programming In JavaScript – Part 2: Inheritance

Inheritance is a major feature of Object Oriented Programming (OOP). It is useful because it allows for code reuse and is also a way of enabling polymorphism. Polymorphism is a bit beyond the scope of this post, but you can read various descriptions about it on the Stack Overflow thread: What is polymorphism?

Inheritance, like most things, is best explained with a real world example. Let’s say we have a company called MegaCorp. MegaCorp has many software systems, that share much base code in common. One such system is the payroll system. On their larger system they have two types of object: an Employee and a Manager. The payroll system will need to be able to generate payslips for both Employees and Managers.

Generating a payslip for either a Manager or an Employee would actually be the same. When it comes to payslips, the fact someone is a Manager is irrelevant. In both cases we just need: their salary, employee ID and Social Security number. This means for the purposes of generating the payslip, an Employee and a Manager are treated in the same way. This is polymorphism. We can also use code reuse here, because the functionality of generating the payslip is identical for both Objects. Let’s look at how we would implement this in JavaScript, then I will explain how it all works.

// Create the constructor function for Employee
function Employee (id, firstName, lastName, socialSecurityNumber, salary) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.socialSecurityNumber = socialSecurityNumber;
    this.salary = salary;
}

// Add the payslip generation function to the prototype of Employee
Employee.prototype.generatePayslip = function () {
    var monthlySalary = this.salary / 12;
    return "Employee ID : " + this.id
    + "\n"
    + "Name : " + this.firstName + " " + this.lastName
    + "\n"
    + "Social Security Number : " + this.socialSecurityNumber
    + "\n"
    + "Pay : $" + monthlySalary;
};

// Create the constructor function for Manager.
// It makes use of the Employee constructor
// by using the call function
function Manager (id, firstName, lastName, socialSecurityNumber, salary) {
    Employee.call(this, id, firstName, lastName, socialSecurityNumber, salary);
    this.managedEmployees = [];
}

// Create a copy of Employee's prototype and
// assign it Manager's prototype.
// This will give Manager the generatePayslip function
Manager.prototype = Object.create(Employee.prototype);

// Give the manager more functionality than the employee
// In other words, extend the functionality
Manager.prototype.addManagedEmployee = function (employee) {
    this.managedEmployees.push(employee);
};

Manager.prototype.removeManagedEmployee = function (employee) {
    this.managedEmployees.filter(function (e) {
        return e.id !== employee.id;
    });
};

Manager.prototype.constructor = Manager;

// Create a new employee instance
var anEmployee = new Employee(123, 'John', 'Smith', 99090, 60000.00);

// Create a new manager instance
var aManager = new Manager(113, 'Frank', 'Pointyhair', 88454, 90000.00);

console.log(anEmployee.generatePayslip());
/*
"Employee ID : 123
Name : John Smith
Social Security Number : 99090
Pay : $5000"
*/

console.log(aManager.generatePayslip());
/*
"Employee ID : 113
Name : Frank Pointyhair
Social Security Number : 88454
Pay : $7500"
*/

Now the explanation.

We start by creating an Employee constructor function, which sets all the properties of the object, then we add a generatePayslip function to Employee’s prototype. This should be familiar to anyone who has read the first post in this series.

Next is where things get interesting. We create a Manager constructor function. We want Manager’s to have all the functionality that an Employee has, but then some extra functionality that is specific to only Managers. We use inheritance to achieve this.

The first piece of inheritance magic is in Manager’s constructor. We call Employee.call(this, args1 … argsn). call is a function which automatically exists as a property on all functions (including the Employee constructor function). It is used to call the function in a given context (ie on a given object), with the given arguments. The first argument is the object we want the context to be. In this case we pass ‘this’, which will be the current Manager instance. The other arguments are all the arguments that the function being called should take. When we call this the Employee constructor function will be executed in the context of the current Manager object. That means all the properties which get added to ‘this’ in the Employee constructor will get added to the new Manager instance we are creating. This is code reuse in action. We don’t have to write out this.id = id; et al in the Manager constructor, we simply reuse the Employee constructor. Programming is designed to make you lazy… I mean efficient.

The last thing we do in the constructor is add a managedEmployees property to the Manager. By doing this we are said to be extending the functionality of the Employee object for the Manager. If we couldn’t extend the functionality beyond what Employee offered us then creating a new type of object would be pointless, as it could only ever be identical to Employee.

Next we make a call to Object.create(), and this is important. You can find detailed documentation on Object.create at MDN. In a nutshell, Object.create creates a new object that inherits all of the properties from the passed object. Another way of saying this would be that it creates a new object, and sets the given object to be the internal prototype (__proto__) of the newly created object. If you don’t know what an internal prototype is, please read the previous post in this series.

All this means is that when we do:

Manager.prototype = Object.create(Employee.prototype);

We are creating an object that inherits all the properties from Employee.prototype, and setting Manager.prototype to be that object, so all Manager instances therefore will inherit all of the properties from the Employee.prototype. This is very important to us, as it allows us to share the code for the generatePayslip function (which is a property on Employee.prototype) with all instances of Manager. It’s that lazy code reuse again.

Next we simply add a couple of functions to the Manager prototype, addManagedEmployee and removeManagedEmployee. Neither of these functions will exist on the Employee prototype, so again we are extending Manager with new, Manager specific functionality.

The last stage in the inheritance process is setting the constructor property on Manager.prototype to be the Manager constructor function. Since the Manager prototype is inherited from Employee.prototype, the current value will be the Employee constructor function. I’m not sure this step is absolutely necessary, but I include it for correctness.

Finally we create a new Employee and new Manager instance, and show that the generatePayslip function works on both as expected.

The Prototype Chain

The prototype chain is an important concept in JavaScript inheritance, as it determines how inherited properties are resolved. To explain the prototype chain, we’ll use calling aManager.generatePayslip() from the previous code as an example.

When we call this, JavaScript will first check the aManager instance’s own properties for a function called generatePayslip. The instance itself has no such property, so the search continues. Next, JavaScript will check the objects internal prototype object (aka __proto__) for a function called generatePayslip. Again, it will not find such a property on this object. It’s internal prototype will be Manager.prototype which has the addManagedEmployee and removeManagedEmployee functions as properties, but not generatePayslip. Next to be checked is the internal prototype of the internal prototype… Since an internal prototype is also an object, it too has it’s own internal prototype property. It’s third time lucky, as now the function gets found, and executed. This is because when we do Object.create(), the prototype returned has an internal prototype that matches Employee.prototype that has the function on it.

If the function was not found at this stage, there is one final internal prototype to check, and that would have been inherited from Object.prototype. This is the base prototype from which all objects inherit, and so is the last in the list to be checked. If a function is not found here, then we have an error.

This list of prototypes that get searched through are referred to collectively as the prototype chain of an object. To make things clearer, let’s look at aManager’s complete prototype chain:

  • id
  • firstName
  • lastName
  • socialSecurityNumber
  • salary
  • managedEmployees
  • __proto__ (Manager.prototype)
    • addManagedEmployee
    • removeManagedEmployee
    • __proto__ (Employee.prototype)
      • generatePayslip
      • __proto__ (Object.prototype)
        • All of Object.protoype properties here…

The very observant amongst you may be asking why there are no id, firstName, etc properties on the Employee.protoype, after all, employees have these properties. This is quite simple. In the Employee constructor, these properties are added to the new employee instance being created, not to the Employee.prototype.

Next Time

Next time I’ll take you through ES6’s class syntax, explain why these aren’t really classes, and tell you how the new syntax relates to everything you just learned in this post.

Full Series

4 comments

  1. PLEASE DO NOT USE INHERITANCE. This advice is out dated and should no longer be taught. For code reuse please use composition.

Leave a Reply

Your email address will not be published. Required fields are marked *