Object-oriented programming with JavaScript

A short introduction on how to achieve OOP concepts such as classes and inheritance in JavaScript

Classes in my JavaScript?

JavaScript does not have a built-in language construct for the definition of a class; however, we can achieve the same concept of an “object blueprint” via a function, to which attributes and methods can be attached dynamically. Let’s look at a practical example—let’s implement a simple Animal class:

function Animal(name) {
	// Attributes
	this.name = name;

	// Methods
	this.getName = function() {
		return this.name;
	}

	this.setName = function(name) {
		this.name = name;
		return this;
	}

	this.speak = function() {};
	this.toString = function() {};
}

So this class has a name which is encapsulated by a getter and a setter. It also has two undefined methods. Nothing extraordinary here.

Inheritance

Let’s implement a class Cat that extends Animal. This can be done by assigning an instance of Animal to  Cat.prototype:

Cat.prototype = new Animal(); // A Cat is an Animal
function Cat(name, favouriteFood) {
	// This is how we invoke the constructor of the parent class.
	// Not very nice; we will see a way around this.
	Animal.prototype.constructor.call(this, name);

	// Attributes
	this.favouriteFood = favouriteFood;

	// Methods
	this.speak = function() {
		return 'Meow';
	}

	this.toString = function() {
		return this.getName() + ' is a cat';
	}

	this.getFavouriteFood = function() {
		return this.favouriteFood;
	}
}

Instantiating objects and passing messages is straight forward to those who are familiar with C++/Java:

loup = new Cat("Loup", "tuna");

document.write(
	loup + ' who loves ' + loup.getFavouriteFood() + '.' +
	loup.getName() + ' says "' + loup.speak()+ '".'
);

And the output is:

Loup is a cat who loves tuna. Loup says “Meow”.

Notice the overriding of the methods speak() and toString() in the Cat class.

But wait! There’s more!

We can make the invocation of parent constructors a bit more elegant like this:

Cat.prototype = new Animal(); // A Cat is an Animal
Cat.prototype.parent = Animal.prototype;
function Cat(name, favouriteFood) {
	// This is how we invoke the constructor of the parent class.
	// See how this is much better?
	this.parent.constructor.call(this, name);
	…

But now for every inheritance we would need to copy and paste lines 2 and 3. We can reduce code repetition by creating a method as follows:

Function.prototype.extends = function(parentClass) {
	this.prototype = new parentClass();
	this.prototype.parent = parentClass.prototype;
}

Since our classes are actually JavaScript functions, we can add any method or attribute to Function and it will be available to any of our classes. Lines 2 and 3 above are almost exactly as we had before: “Cat” was replaced by “this” and “Animal” was replaced by the reference “parentClass”.

Here is how we would use it:

Cat.extends(Animal); // A Cat is an Animal
function Cat(name, favouriteFood) {
…

That’s it!

The final version of the code can be tested here.

If you don’t want to reinvent the wheel, there are a couple of powerful and robust frameworks out there that will achieve the same functionality and much more. Prototype JS is one of them.

So there you go, this should get you started with OOP in JavaScript!

References: Classical Inheritance in JavaScript by Douglas Crockford and OOP in JS, Part 2 : Inheritance by Gavin Kistner.