Understanding Inheritance and Prototype Chain in JavaScript.

Inheritance is a very important topic when it comes to object oriented programming, by virtue of which children classes inherit from their parent class. But unlike many conventional languages, JavaScript's inheritance is based on prototypes rather than classes.

Before we get started, please keep in mind a function is an object in JavaScript. As it goes with object to have properties, functions have a property called ‘prototype’ property which plays an important role in Prototypal Inheritance ( we will be discussing this property in detail later in the blog ).

  1. Object Creation in JavaScript

In JavaScript, Objects can be created in three possible ways:

  1. An object as literal

Here, we are going to concentrate on the last two ways of object creation.

Using the function constructor

A constructor is a normal function in JavaScript. They are meant to be used to create instances of an object with the“new” keyword.

function Person(name) {
this.name = name;
this.walk = function() {
console.log(this.name + ' is walking.');
}
}
var bob = new Person('Bob');
bob.walk(); // Outputs 'Bob is walking.'
var john = new Person('John');
john.walk(); // Outputs 'John is walking.'

In the above example, we created two object instances bob and john using Person constructor. One point to notice `is that each object has its own walk method. You may want the walk method shared across objects with the value of “this” set to the object calling the method. This can be achieved using “prototype” property of the function object.

function Person(name) {
this.name = name;
}

Person.prototype.walk = function() {
console.log(this.name + ' is walking.');
}

var bob = new Person('Bob');
bob.walk(); // Outputs 'Bob is walking.'
var john = new Person('John');
john.walk(); // Outputs 'John is walking.'

Here, the walk method is not getting copied to each of the object instance. Instead it is part of the prototype of the Person constructor function.

(bob.hasOwnProperty(‘walk’) === false) while bob.walk() gives “Bob is walking”. Let us understand how this is working:

  1. When we call bob.walk(), it looks for the walk function in the properties of bob.

This is referred as Prototype Chain.

Using Object.Create()

With Object.Create() JavaScript provided a new function to create object in ES5.

Some important points about Object.create() are as follows:

  • This method takes two arguments .The first argument is the prototype of the object to be inherited, and is the required argument. To create an empty object, you must pass the Object.prototype as the first argument.
var person= {
walk: function() {
console.log(this.name + ' is walking.');
}
};
var bob = Object.create(person, {
name: { value: "Bob" }
});

In this case we first define the prototype object person, and then we use Object.create to make a new object which inherits from person. That second argument might look a little strange, but it's just a simple property descriptor object. Inheritance managed by Object.create can't be detected by instanceof. Instead you'll need to use the isPrototypeOf method.

2. Classical Inheritance vs Prototypal Inheritance.

Prototypal Inheritance is dynamic

You can add new properties to prototypes after they are created. This allows you to add new methods to a prototype which will be automatically made available to all the objects which delegate to that prototype.

This is not possible in classical inheritance because once a class is created you can’t modify it at run time. This is probably the biggest advantage of prototypal inheritance over classical inheritance.

Prototypal inheritance is just as powerful as classical inheritance

JavaScript supports multiple inheritance. There are actually two ways to implement prototypal inheritance:

  1. Delegation or Differential Inheritance

Differential Inheritance is same as what we discussed above ( looking through the prototype chain ).

Concatenative inheritance is the process of copying the properties from one object to another, without retaining a reference between the two objects. With the introduction of ES6, it is achieved using Object.assign() . The method which is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

Object.assign(target, ...sources)var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.

However, Properties on the prototype chain and non-enumerable properties cannot be copied.

var obj = Object.create({ foo: 1 }, { // foo is on obj's prototype chain.
bar: {
value: 2 // bar is a non-enumerable property.
},
baz: {
value: 3,
enumerable: true // baz is an own enumerable property.
}
});

var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

Developers from the classical background argue classical inheritance is more powerful as it has private variables. Even Javascript supports private variables using Closures and with the introduction of let and const in ES6 we have block scoping available as well.

This is my first attempt to put my understanding into words. Thanks for reading.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Akash Verma

Akash Verma

JavaScript Enthusiast, Software Engineer @goevive. Follow me on twitter @Akash940