Thursday, October 8, 2015

Prototypal Inheritance in Javascript

In today's blog post I will be discussing the prototypal inheritance in JavaScript.

Prototypal Inheritance in JavaScript

In most languages (like Java, C#, etc) inheritance is class based. We derive one class from another to reuse the pre-written code and establish hierarchy of different types so we can use them easily throughout our application.


Prototypal Inheritance in Javascript

JavaScript does not have concept of classes. The object themselves carry their data and capabilities. The lineage of the object doesn't matter, only what they can do. JavaScript is a prototypal language i.e. objects inherit from one another.

Let's understand this one by one with examples. The first thing that we need to understand is that functions in JavaScript are objects. So if we have a function named person, we can add any property to it, e.g. type.
 
function person(){}
person.type = 'employee';
console.log(person.type);    //employee

Next, I want the person to be of different types. So I add a type property and return that object.

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

var employee = new Person('employee');
var manager = new Person('manager');

console.log(employee.type);      //employee
console.log(manager.type);        //manager

Please note that this time the function name is capitalized. It's just a convention followed by JavaScript developers that this function needs to be used with new keyword to create instance of Person (I will be writing blog post on constructor invocation next week). So I added this property called type which we pass when we create the object. So we passed 'employee' and 'manager' as the type in the constructor. Invoking new Person('employee') returns the "this" object with type property set to the parameter value.


Next, I want to add smile method to the Person. So you might think by adding it to Person should suffice like this:

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

Person.smile = function(){
    console.log("Smile");
}

var employee = new Person('employee');

console.log(employee.smile());       //employee.smile is not a function
console.log(employee.__proto__);  //contains no smile method   
console.log(Person.smile());           //Smile


As you can see by adding it to Person object, we don't automatically add it to the instances of the Person object. The smile method is available on Person but not on employee. The reason being when we call new Person('employee'), we return the "this" object which has only one property called type defined. Since Person.prototype does not have smile method and employee.__proto__ is created from Person.prototype we will find that there is no smile method in employee.__proto__ as well.

The way Javascript works is, when we look for a property or a method on an object, it's looked up in the following order:

1. employee object has smile method()
2. Employee.prototype has smile method() defined explicitly
3. Person prototype has smile method. Since employee prototype is created using Person prototype object (inheritance).


So, one simple way of adding the smile method to returned objects can be this:

function Person(type){
   this.type = type;
   this.smile = function(){
    console.log("Smile");
    }
}

var employee = new Person('employee');
var manager = new Person('manager');

console.log(employee.smile());          //Smile
console.log(manager.smile());            //Smile


Another way of accomplishing the same thing (which we are more interested in) can be by adding it to the Person's prototype like this:

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

var employee = new Person('employee');
var manager = new Person('manager');

Person.prototype.smile = function(){
    console.log("Smile");
}


console.log(employee.smile());      //Smile
console.log(employee.__proto__); //contains smile method
console.log(manager.smile());        //Smile

Now employee and manager have smile method. This time, the smile method was defined in Person prototype which sets the employee and manager's prototype. Voila, this way we were able to inherit using prototype. 

Now, let's just use the type property inside the smile method to show which type of employee is calling the smile method:

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

var employee = new Person('employee');
var manager = new Person('manager');

Person.prototype.smile = function(){
    console.log("This is "+ this.type +  " smile");
}

console.log(employee.smile());   //This is employee smile
console.log(manager.smile());     //This is manager smile

Next, to further improve, if we want to have separate function for Employee, we can do like this:

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

Person.prototype.smile = function(){
    console.log("This is "+ this.type +  " smile");
}

function Employee(){
    //calling constructor and passing "employee" as type
    Person.call(this, 'employee');
}

Employee.prototype = Object.create(Person.prototype);

var employee = new Employee();

console.log(employee.smile());     //Smile

Here, we created Employee function which returns a Person object and passes "employee" as type. Here, we set the Employee prototype explicitly to create an object using Person prototype. As a result, we inherit everything from Person's prototype. This is what happened internally in the previous examples we saw where smile() was inherited from Person's prototype.

Conclusion

The prototypal inheritance is a powerful concept and it's very different from other common languages like C# and Java. That is why its very important to understand this properly.
So in this article we saw how to implement inheritance in JavaScript and understood the underlying concept.

Image Ref: here

For future updates to my weekly blog, please subscribe to my blog via the "Subscribe To Weekly Post" feature at the right and follow me on Twitter. Until then Happy Coding :)

No comments:

Post a Comment