View Screencast | Download code

This post is basically a summary of the screencast, which contains more details and explanations.

I’ve shown how to create inheritance in JavaScript, both for properties and methods. Now, I’m going to talk about method overrides. That is, I want to be able to replace a method of an ancestor class with a method of the same name from a descendant class, while still having access to the original method. JavaScript does not inherently allow for this, but we can make it work. I’m going to be building on my prior examples, so you might want to take a look at some of the previous posts in this series.

For reference, here is the class hierarchy again.

Figure 1 - Class Diagram

Figure 1 - Class Diagram

I’m going to override the getFullName method of the Person class, with a modified version in the Employee class. For reference, here is the Person class again. Incidentally, the use of the inheriting object was covered in the previous post on method inheritance.

1
2
3
4
5
6
7
8
9
10
11
var inheriting = { };
 
function Person(first, last) {
  if (arguments[0] === inheriting) return;
  this.firstName = first;
  this.lastName = last;
};
 
Person.prototype.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
};

The Person class getFullName method returns the full name in the form “FirstName LastName”, but I want the Employee class to return it as “LastName, FirstName”. Straight overriding (i.e. replacing) of methods is easy in JavaScript. Just redefine the method in the descendant class.

1
2
3
4
5
6
7
8
9
10
11
12
function Employee(first, last, company) {
  if (arguments[0] === inheriting) return;
  Person.call(this, first, last);
  this.company = company;
};
 
Employee.prototype = new Person(inheriting);
 
// Overrides Person
Employee.prototype.getFullName = function() {
    return this.lastName + ', ' + this.firstName;
};

Line 10 is where I replace the getFullName method with the version for Employee. This does not, however, let me access the original version of the method from the base class, Person. In order to do that, I need to have a reference to the original method in the Person class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Employee(first, last, company) {
  if (arguments[0] === inheriting) return;
  Person.call(this, first, last);
  this.company = company;
};
 
Employee.prototype = new Person(inheriting);
 
Employee.base = Person.prototype;
 
// Overrides Person
Employee.prototype.getFullName = function(firstLastFormat) {
  if (firstLastFormat)
    return Employee.base.getFullName.call(this);
  else
    return this.lastName + ', ' + this.firstName;
};

Line 9 adds the reference to the original Person.prototype methods. So now I can access them from Employee.base, as in line 14. Note that I have to use the JavaScript call function in order to have the base class method executed against my Employee instance (referenced by the this variable). If you are not familiar with the call method, I covered its use in Part 2 of this series.

Now when Employee.getFullName() is called, it checks to see if the firstLastFormat argument is true and, if it is, calls the base class (in this case Person) getFullName method.

This mechanism also works through multiple levels of the class hierarchy. For example, we could further override the getFullName method in the Manager class (which inherits from the Employee class).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Manager(first, last, company) {
  Employee.call(this, first, last, company);
  this.workers = [];
};
 
Manager.prototype = new Employee(inheriting);
 
Manager.base = Employee.prototype;
 
// Overrides Employee
Manager.prototype.getFullName = function(firstLastFormat) {
  var name = Manager.base.getFullName.call(this, firstLastFormat)
  return name + ' (' + this.company + ')';
};

Note in line 8 that the Manager.base property references the Employee.prototype property. Therefore, line 12 calls the version of getFullName that is part of the Employee class. If firstLastFormat was passed with a value of true, then Employee.getFullName will call Person.getFullName. It all works, right through the class hierarchy.

In my next post, I think its about time to simplify all of this by creating a JavaScript object that will handle all this inheritance stuff for me. Yes, this will be very similar to what other libraries already provide. But it is so much more fun and educational to code it ourselves, isn’t it?