JavaScript Inheritance – Explained

In a classical Object Oriented world, the inheritance has a very well defined expectation. 

  • Code Reuse, where a derived class makes use of the accessible properties and methods and declares or overrides methods / properties which are specific to the derived class.
  • Type Structure, where the derived class has a defined type, related to the parent class.

JavaScript being loosely typed, doesn’t give too much importance to the second point. It stays focused on what the given object can do, instead of who is its parent.

Assumptions

This article assumes that

Prototype-based Programming

Prototype-based programming allows you to implement inheritance through reuse of existing objects that serve as prototypes, through Delegation.

As part of Delegation, the property or methods of an object (the receiving object) get evaluated in the context of another object (the original object). There are two types of delegation:

  • Explicit Delegation: by explicitly passing the original object to the receiving object
  • Implicit Delegation: by using the member lookup rules of the language

In case of prototype-based programming, primarily the implicit delegation is used. By using the prototype keyword on the object, you specify the object from which it can inherit properties and methods.

Inheritance

Let’s start with the code, where we have a Blog object, which is the more generic object (let’s call this base object) and TechnicalBlog, which is the more specific object (let’s call this the derived object).

var Blog = function(blogName, authorName) {
    this.blogName = blogName;
    this.authorName = authorName;
    this.saveDraft = function() {
     console.log("Saving the draft version for " + this.blogName );
    }
}
Blog.prototype.publish = function(publishDate) {
console.log('The blog will be published on: ' + publishDate + ", by " + this.authorName);
};
var TechnicalBlog = function(technologyName, blogName, authorName) {
    this.technologyName = technologyName;
    Blog.call(this, blogName, authorName);
};
TechnicalBlog.prototype = new Blog();
TechnicalBlog.prototype.constructor = TechnicalBlog;
var inheritanceBlog = new TechnicalBlog("Javascript", "Inheritance in Javascript", "Abhilasha Sinha");
inheritanceBlog.saveDraft();
inheritanceBlog.publish( new Date());
console.log("The constructor is : " + inheritanceBlog.constructor);

What did we do?

In above code, we used Blog.call and passed the “this” as argument on which the Blog’s constructor shall apply all the properties and methods. Also, we passed other arguments which the Blog constructor expects. By doing this we made sure that the initialized property of the original object becomes available to the new object as well.

Also, we used the following code to let the new object know that its prototype shall point to Blog so that this object can access the methods available to the original objects:

TechnicalBlog.prototype = new Blog();

Finally, we have set the constructor property explicitly to indicate that this Object should consider TechnicalBlog as a constructor, instead of Blog.

Notes

  • Try commenting following lines of code, one after another and notice the difference in the output on your browser console:
    • // Blog.call(this, blogName, authorName);
      • You will note that all the properties and methods are available. However, they are not initialized. This is because you have set the prototype to an instance of Blog object.
    • // TechnicalBlog.prototype = new Blog();
      • You would note that the saveDraft method is available. However, the publish method is no longer available
      • When you comment this line then Object becomes the default prototype, which is the default prototype for all the objects
    • // TechnicalBlog.prototype.constructor = TechnicalBlog;
      • The constructor code for the TechnicalBlog is same as Blog object

 

Adding new properties to an existing object

Let’s add following lines of code towards the end and observe the output:

inheritanceBlog.prototype.updateCount = 1;
console.log( "Assigning property value on instance : " + inheritanceBlog.updateCount);

When you check the console, it gives following error:

Uncaught TypeError: Cannot set property 'updateCount' of undefined

Basically you tried to lookup for a property updateCount using an existing object inheritanceBlog. Since the prototype doesn’t contain this property, it was considered undefined.

Hence, if you need to add new property or method in a specific instance of the object then you should do as shown below:

inheritanceBlog.updateCount = 1;
console.log( "Assigning property on specific instance : " + inheritanceBlog.updateCount);

Note

  • There are situations when you do need to know if the property belongs to the same instance or is it obtained from the prototype object. You can make use of method like hasOwnProperty for the same.

Adding a new property to all the instances derived from an object:

Let’s consider following code and observe the output on the console

inheritanceBlog.updateCount = 1;

console.log( "Assigning property on specific instance : " + inheritanceBlog.updateCount);

var bestPracticeBlog = new TechnicalBlog("Javascript", "Javascript Best Practices", "Abhilasha Sinha");

console.log( "Checking availability of property on one more object: " + bestPracticeBlog.updateCount);

It shows following as output:

Assigning property on specific instance : 4
Checking availability of property on one more object: undefined

Note that the updateCount variable was defined on the specific blog instance, i.e. inheritanceBlog and hence it is not available on other instance.

Now let’s work with the code a bit and add the new property in the parent object’s prototype.

TechnicalBlog.prototype.updateCount = 1;
inheritanceBlog.updateCount += 3;
console.log( "Assigning property on specific instance : " + inheritanceBlog.updateCount);

var bestPracticeBlog = new TechnicalBlog("Javascript", "Javascript Best Practices", "Abhilasha Sinha");
bestPracticeBlog.updateCount += 5;
console.log( "Checking availability of property on one more object: " + bestPracticeBlog.updateCount);

The output looks as shown below:

Assigning property on specific instance : 4

Checking availability of property on one more object: 6

Now the updateCount property became available for all the objects whose prototype is TechnicalBlog. Also, all the objects will start maintaining their own copy, the moment the first lookup happens.

Note

  • As you would expect, modification in one instance will not impact the value in other instance
    • First time the objects take value from the prototype object
    • Subsequently it uses its own value
  • Same way you can define methods as well and make them available for all the derived objects

Adding a new property in the parent object

Let’s add a following code in the previous example and understand the impact:

TechnicalBlog.lastUpdatedDate = new Date(); 

console.log( "Last Updated Date for an existing blog:" + bestPracticeBlog.lastUpdatedDate);

It gives you the following output, which indicates that the lastUpdatedDate property is not available for the existing objects:

Last Updated Date for an existing blog:undefined

Now consider following code:

TechnicalBlog.lastUpdatedDate = new Date();
TechnicalBlog.getLastUpdatedDate = function() {
return this.lastUpdatedDate;
};

var designPatternBlog = new TechnicalBlog("Javascript", "Javascript Design Pattern", "Abhilasha Sinha");

console.log("The last update date on parent object is " + TechnicalBlog.lastUpdatedDate);
console.log( "Checking availability of property on the new object: " + designPatternBlog.lastUpdatedDate);
console.log("The last update date on parent object is " + TechnicalBlog.getLastUpdatedDate());

 

It gives you the following output:

The last update date on parent object is Sun Jul 02 2017 17:01:32 GMT+0530 (IST)

Checking availability of property on the new object: undefined

The last update date on parent object is Sun Jul 02 2017 17:01:32 GMT+0530 (IST)

If you add a new property or method on the parent object, instead of its prototype or inside the constructor function, then it will not be available for the derived object. As expected, the new property is available on the parent object.

Bonus Notes

Try adding following method in the TechnicalBlog construction function and use this to check the last updated date in the above example:

this.getUpdatedDate = function() {
return this.lastUpdatedDate;
};

The prototype keyword – a closer look

The keyword prototype doesn’t give an idea that this will help us in achieving inheritance. However, if you look at the true meaning of prototype, which means a first or preliminary version of a device from which other forms are developed then you would be able to make sense. So, the more primitive objects are the prototypes for the more explicit object, which uses the behaviour of the more general (primitive) objects.

Interestingly, whether you mention this keyword or not, every object is linked to a prototype. For example in below code, by default the prototype is the Object object, which comes by default in JavaScript:

var Blog = function(blogName) {
    this.name = name;
    this.content = “”;
 }

console.log(Blog.prototype);

Expand the console log and you would find following details:

inheritence

You can assume that every object has access to these properties and methods. Also, you would like to expand this and go through below URL to know details about each of these properties:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype

Property Lookup using Prototype Chain

By now you must have understood that prototype allows you to mention the object from which you can borrow the properties and methods.

Following diagram explains how JavaScript looks up for the properties and methods being invoked at the runtime:

inheritence2

Above approach means that unlike classical OOP, the Javascript instances don’t need to define each methods within an instance (i.e. it doesn’t need to copy the methods and properties defined in the prototype chain in the instance). It just needs to know about its prototype object and the efficient lookup ensures that it is able to identify and parse the invoked method quickly.

Hiding the Prototype during inheritance

Achieving inheritance through the use of prototype looks like a difficult pill to chew. In true sense, it is more of a delegation rather than inheritance. Hence, different frameworks and libraries comes up with their own way of making it more readable and attractive. What they do is that they define developer friendly methods like extend or inherit and recommends developers to use the same.

For example, below code shows how you can inherit from an object using the extend method, instead of using the prototype keyword:

Function.method(‘extends’, function (Parent) { 
this.prototype = new Parent();
return this;
}); 

And, you can use extend as shown in below code:

var Blog = function(blogName) {
    this.name = name;
    this.content = “”;
    This.publish = function(publishDate) {
console.log(‘The blog will be published on’ + publishDate);
}
}

var TechnicalBlog = function(technology) {
     this.technology = technology;
}.extends(Blog);

Of course, by making use of the cascading, we made this a bit more readable and people from traditional OO background will have a bit less concern. But, you still need to digest the true concept and power of prototype to be able to make effective use of Inheritance in JavaScript.

Notes

  • The Function.prototype.methodName allows you to add a new method to all the functions in Javascript
  • Similarly adding anything using Object.prototype makes that property and methods available to all the objects

Important Notes

  • While I am writing this, EcmaScript6, have introduced the concept of class. However, it is yet to be standardized and hence, this article is still in the context of the current state of JavaScript
  • Don’t modify or override the prototypes of the standard JavaScript objects.

Read More

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s