in Javascript

Simple cross-browser inheritance with Javascript

There are multiple ways to implement object classes in Javascript, especially since ECMAScript6 (ES6) emerged. Unfortunately, ES6 is not supported by old browers (you know, the old shitty ones that almost all of our customers don’t want to get rid of since they’re “more secure” LOL) and the legacy implementations are more of a hack than proper object-oriented programming.

Implementing object and classes is a deal, but inheritance is a real challenge. Or it isn’t.

Here is a simple way to do proper class inheritance in Javascript that works even in old browsers.

All the magic resides in the prototype.

Let’s start with a parent class ClassA :

/**
 * @class ClassA
 * @param {string} [name]
 */
var ClassA = function(name) {
  this.name = name || "Name A";
};

/**
 * Print out object information in the console
 */
ClassA.prototype.print = function() {
  console.log("Name:", this.name);
};

All the methods of ClassA reside in its protoype. To create a child class of ClassB with all the methods from ClassA, the best way is to create it’s prototype from the prototype of an object instance of ClassA.

child.prototype = Object.create(parent.prototype);

This may look weird at the first glance but this is the actual way legacy Javascript inheritance works.

Let’s try it by implementing a child class ClassB :

/**
 * @class ClassB
 * @augments ClassA
 * @param {string} [name]
 * @param {string} [surname]
 */
var ClassB = function(name, surname) {
	ClassA.call(this, name || "Name B"); // Call parent constructor
	this.surname = surname || "Surname B";
};

// Set parent prototype
ClassB.prototype = Object.create(ClassA.prototype);

/**
 * Print out object information in the console
 */
ClassB.prototype.print = function() {
	ClassA.prototype.print.call(this);
	console.log("Surname:", this.surname);
};

Test it out :

var b = new ClassB();
b.print();

Result :

Name: Name B 
Surname: Surname B

Here what the object b looks like with the browser’s Javascript inspector :

As you can see, the two prototypes __proto__ are chained. ClassB‘s print() function overrides ClassA‘s.

But there is one issue, the constructor() method that is created by default while implementing the class has been erased in the process and the constructor method for object b is now ClassA() while it should be ClassB() :

b.constructor
function ClassA()

You need to explicitly set the constructor of the child class just after setting the parent prototype :
child.prototype.constructor = child;

With our example :

ClassB.prototype.constructor = ClassB;

We now have the proper constructor for object b.

For a better readability of the code, we can implement an extend() function to do the job :

/**
 * Extend child class from parent class.
 * @param {function} child - Child class to extend from the parent
 * @param {function} parent - Parent class
 * @return {function} The extended child class
 */
var extend = function(child, parent) {
	// Set parent prototype
	child.prototype = Object.create(parent.prototype);

	// Set child class constructor
	child.prototype.constructor = child;

	return child;
};

The extend() function can now be called while implementing child classes :

/**
 * @class ClassB
 * @augments ClassA
 * @param {string} [name]
 * @param {string} [surname]
 */
var ClassB = extend(function(name, surname) {
	ClassA.call(this, name || "Name B"); // Call parent constructor
	this.surname = surname || "Surname B";
}, ClassA);

/**
 * Print out object information in the console
 */
ClassB.prototype.print = function() {
	ClassA.prototype.print.call(this);
	console.log("Surname:", this.surname);
};