JavaScript

JavaScript Inheritance Example

EDITORIAL NOTE: In this post, we feature a comprehensive JavaScript Inheritance Example. In object-oriented programming, inheritance enables new objects to take on the properties of existing objects. A class that is used as the basis for inheritance is called a super-class or base class. A class that inherits from a super-class is called a subclass or derived class.

JavaScript is a very popular object-oriented language. We use it every day in our web applications, it is also supported on many user interface (UI) frameworks like QT, and on server side applications (node.js).

However this language is prototype based and does not implement a traditional class system. This is often confusing for developers whose are familiar with languages that support the concept of classes like Java or PHP.

In this article, we will discuss inheritance in JavaScript.

1. Introduction

Most languages have classes which are like blueprints to create object instances. Those classes can inherit from other classes and the only way to create a new kind of object is by defining a new class.

JavaScript’s prototype-based inheritance means that an object inherits from another object. This is known as the prototype chain and also means that objects are dynamic “bags” of properties (referred to as own properties), in other words objects in JavaScript behave like dictionaries in other languages so you can “add” new items to the dictionary at any time.

The prototype chain works as follows: each object has an internal link to another object called its [[Prototype]]. That prototype object has a [[Prototype]] of its own, and so on until an object is reached with null as its [[Prototype]]. null, is the end of the chain and by definition has no [[Prototype]] property.

Tip
Following the ECMAScript standard, the notation someObject.[[Prototype]] is used to designate the prototype of someObject. This is equivalent to the JavaScript property __proto__ (now deprecated). Since ECMAScript 5, the [[Prototype]] is accessed using the accessors Object.getPrototypeOf() and Object.setPrototypeOf().

TOC

2. Tools we are going to use

I am using the following tools:

  1. sublime text 3
  2. node.js v0.10.33
  3. GNU/Linux distro (Ubuntu)

So lets create a new project:

mkdir -p ~/Projects/js-inheritance-example
cd ~/Project/js-inheritance-example
npm init # follow the on screen instructions and don't forget add "private": true to the package.json so that your project is not globally distributed as a npm app.

Here is how my package.json file looks like:

{
  "name": "js-inheritance-example",
  "version": "1.0.0",
  "description": "JavaScript inheritance example",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Eivar Montenegro <e.mont01 at gmail.com>",
  "license": "MIT",
  "private": true
}

You can execute any .js file from your console using the following command:

node file_name.js

TOC

3. Inheritance and the prototype chain

At the end of any prototype chain, we normally find an Object whose prototype is null. Null, as mentioned before, marks the end of our prototype chain, now lets see some examples:

Let’s create a new file and name it objects.js, then add the following code:

/**
 * Syntax constructs: myObject is created and its [[Prototype]] is defined as Object.prototype, so it inherits the method hasOwnProperty among others.
 * Prototype chain: myObject --> Object.prototype --> null
 *
 * @type {Object}
 */
var myObject = {
	prop1: 1,
	prop2: "Hello world"
};

/**
 * Syntax construct: myArray is an array object that inherits from Array.prototype which has methods like indexOf, forEach, etc.
 * Prototype chain: myArray --> Array.prototype --> Object.prototype --> null
 *
 * @type {Array}
 */
var myArray = ['Hello', 'world'];

/**
 * Syntax constructs: myFunction inherits from Function.prototype, which has methods like call, bind, etc.
 * Property chain: myFunction --> Function.prototype --> Object.prototype --> null
 *
 * @type {Function}
 * @return {string}
 */
function myFunction() {
	return 'Hello world';
}

/**
 * Constructor: As seen before Triangle itself is an function object but in this case we are using that function as a constructor.
 * Prototype chain: t --> Triangle.prototype --> Object.prototype --> null
 * @param {number} a
 * @param {number} b
 * @param {number} c
 */
function Triangle(a, b, c) {
	this.a = a;
	this.b = b;
	this.c = c;
}

/**
 * Triangle prototype (anonymous object)
 * @type {Object}
 */
Triangle.prototype = {
	perimeter: function () {
		return this.a + this.b + this.c;
	}
}

/**
 * When new Triangle() is executed, t gets its own properties 'a', 'b' and 'c' and t.[[Prototype]] is the value of Triangle.prototype so we can use: t.perimeter()
 * @type {Triangle}
 */
var myVar = new Triangle();

/**
 * ECMAScript 5 Object.create(): calling this method creates a new object, setting the prototype of the new object as the first argument of the function.
 * Prototype chain: mySecondObject --> myObject --> Object.prototype --> null
 *
 * @type {Object}
 */
var mySecondObject = Object.create(myObject);

This code illustrates the 3 ways to create objects in JavaScript, using the syntax constructs like {} or [], you can also create a function that you can use as a constructor or you can use the Object.create method.

My personal recommendation is to use the constructor function.

You can create an object that does not inherit from object using Object.create, as seen in the following example:

/**
 * Prototype chain: o --> null;
 * @type {object}
 */
var o = Object.create(null);

TOC

3.1 Inheriting properties

In JavaScript almost everything is an object, and you can think of as a sort of associative arrays or dictionaries, whose properties can be accessed with obj.propertyName or obj['propertyName']. When you request a property, the instance object will be checked if it does not contain such property, then JavaScript will go through the prototype chain until it either finds the property, or the end of the chain is reached.

Let’s illustrate this using probably the most common example of inheritance: “Living Beings”.

'use strict';

/**
 * Constructor for any living being
 * Prototype chain: LivingBeing --> Object.prototype --> null
 */
function LivingBeing () {
	this.isAlive = true;
	this.birthday = new Date();
	this.legs = 0;
	this.diet = '-';
}

/**
 * Mammals
 * Prototype chain: Mammal --> LivingBeing.prototype --> Object.prototype --> null
 */
function Mammal() {
	LivingBeing.call(this);
	this.bodyTemperature = 30;
}

// Mammals inherit from LivingBeing
Mammal.prototype = Object.create(LivingBeing.prototype);
Mammal.prototype.constructor = Mammal;

/**
 * Felines
 * Prototype chain: Feline --> Mammal.prototype --> LivingBeing.prototype --> Object.prototype --> null
 */
function Feline() {
	Mammal.call(this);
	this.diet = 'Meat';
	this.legs = 4
}

Feline.prototype = Object.create(Mammal.prototype);
Feline.prototype.constructor = Feline;
Tip
The “use strict” directive is new in JavaScript 1.8.5 (ECMAScript version 5). It is not an statement, but a literal expression, ignored by earlier versions of the language, its purpose is to indicate that the code should be executed in “strict mode”.

At this point our Feline function inherits from Mammal whose in turn inherits from LivingBeing, in other words all the properties of LivingBeing and Mammal are present in Feline. One important thing to notice is that you can make Feline to inherit from many other objects doing something like:

function Feline() {
	Mammal.call(this);
	Carnivore.call(this); // lets assume that you have a function named Carnivore
	this.legs = 4;
}

TOC

3.2 Inheriting methods

JavaScript does not have “methods” in the form that class-based languages define them. In JavaScript a method can be added to an object just like any normal property, and if you have two properties with the same name in the prototype chain the first one found will be used and any other one upper in the chain will be ignored, this is called “property shadowing”.

Let’s update the previous example to add a few methods:

'use strict';

/**
 * Constructor for any living being
 * Prototype chain: LivingBeing --> Object.prototype --> null
 */
function LivingBeing () {
	this.isAlive = true;
	this.birthday = new Date();
	this.legs = 0;
	this.diet = '-';
}

LivingBeing.prototype.move = function (distance, direction) {
	console.error('Sorry this living being can\'t move');
}

/**
 * Mammals
 * Prototype chain: Mammal --> LivingBeing.prototype --> Object.prototype --> null
 */
function Mammal() {
	LivingBeing.call(this);
	this.bodyTemperature = 30;
}

// Mammals inherit from LivingBeing
Mammal.prototype = Object.create(LivingBeing.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.move = function (distance, direction) {
	console.log('Walking ' + distance + ' ' + direction);
}
Mammal.prototype.walk = function (distance, direction) {
	this.move(distance, direction);
}

/**
 * Felines
 * Prototype chain: Feline --> Mammal.prototype --> LivingBeing.prototype --> Object.prototype --> null
 */
function Feline() {
	Mammal.call(this);
	this.diet = 'Meat';
	this.legs = 4
}

Feline.prototype = Object.create(Mammal.prototype);
Feline.prototype.constructor = Feline;

Now we added the ability to move around in our LivingThing. However, many living creatures don’t actually move but stay in the same place or perhaps they just drift on a current, so the default implementation just print an error message.

Let’s create a quick test of our code:

var grumpyCat = new Feline();
grumpyCat.walk('1 meter', 'north');

var coralReef = new LivingBeing();
coralReef.move('1 meter', 'south');

The previous code will print the following:

Walking 1 meter north
Sorry this living being can't move

TOC

4. The Complete example

So here is the full code for this example:

'use strict';

/**
 * Constructor for any living being
 * Prototype chain: LivingBeing --> Object.prototype --> null
 */
function LivingBeing () {
	this.isAlive = true;
	this.birthday = new Date();
	this.legs = 0;
	this.diet = '-';
}

LivingBeing.prototype.move = function (distance, direction) {
	console.error('Sorry this living being can\'t move');
}

/**
 * Mammals
 * Prototype chain: Mammal --> LivingBeing.prototype --> Object.prototype --> null
 */
function Mammal() {
	LivingBeing.call(this);
	this.bodyTemperature = 30;
}

// Mammals inherit from LivingBeing
Mammal.prototype = Object.create(LivingBeing.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.move = function (distance, direction) {
	console.log('Walking ' + distance + ' ' + direction);
}
Mammal.prototype.walk = function (distance, direction) {
	this.move(distance, direction);
}

/**
 * Felines
 * Prototype chain: Feline --> Mammal.prototype --> LivingBeing.prototype --> Object.prototype --> null
 */
function Feline() {
	Mammal.call(this);
	this.diet = 'Meat';
	this.legs = 4
}

Feline.prototype = Object.create(Mammal.prototype);
Feline.prototype.constructor = Feline;

function Bird () {
	LivingBeing.call(this);
	this.legs = 2;
	this.wings = 2;
}

Bird.prototype = Object.create(LivingBeing.prototype);
Bird.prototype.constructor = Bird;
Bird.prototype.move = function(distance, direction) {
	console.log('Flying ' + distance + ' ' + direction);
}
Bird.prototype.fly = Bird.prototype.move;

function Parrot () {
	Bird.call(this);
	this.diet = 'Birdseed';
}

Parrot.prototype = Object.create(Bird.prototype);
Parrot.prototype.constructor = Parrot;

var grumpyCat = new Feline();
grumpyCat.walk('1 meter', 'north');

var coralReef = new LivingBeing();
coralReef.move('1 meter', 'south');

var blue = new Parrot();
blue.fly('1 Km', 'east');

function printPrototypeChain(name, object)
{
	console.log('Prototype chain:\n');
	var prototypeObject = Object.getPrototypeOf(object);
	do {
		console.log('--');
		Object.getOwnPropertyNames(prototypeObject).forEach(function(propertyName, idx, array) {
			console.log(propertyName + ' -> ' + prototypeObject[propertyName]);
		});
		prototypeObject = Object.getPrototypeOf(prototypeObject);
	} while (prototypeObject !== null);
	console.log('\n');
}

/**
 * Let's just print the entire prototype chain
 */
printPrototypeChain('LivingBeing', coralReef);
printPrototypeChain('Feline', grumpyCat);
printPrototypeChain('Parrot', blue);

We have added two more constructors namely: Bird and Parrot and a new implementation of move, in this case for birds and also we created an new property called fly to which we just assigned the value of move property so fly can be called like any other method.

There is also a new function named ‘printPrototypeChain’ that you can use to see the entire prototype chain for any given object.
TOC

5. Download

Download
You can download the full source code of this example here: JavaScript Inheritance Example

TOC

Eivar Montenegro

Eivar has graduated from the Faculty of Computer Systems Engineering from the technological University of Panama. During his career he has been involved in numerous projects ranging from programming and design of information systems, billing platforms, social networks, mobile applications and web applications. He works as an independent software consultant and is mainly involved with projects based on web technologies like Wordpress, Laravel, Servlets (Java), HTML5, CSS3 and Javascript.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button