JavaScript: An In-Depth Look at Prototypal Inheritance

All classes in JavaScript are inherited from the Object class.

Whenever we look up a property on an object, Object.

prototype is the extent to which the lookup process goes.

In other words:Object is the base class for all classes in Javascript and therefore, Object.

prototype is the root of the prototypal chain.

If that property doesn’t exist even on Object.

prototype, then it is deemed to not exist.

Let’s check out a simple real-world example of prototype chaining which most of us would have used:var arr = new Array(1, 2, 3);arr.

forEach(function(item) { console.

log(item);});When arr.

forEach is executed, JavaScript first checks if forEach exists directly on arr.

It doesn’t, so it checks arr.

__proto__ internally, which points to Array.

prototype since Array is the function constructor of arr.

It finds forEach there and invokes it.

toString is another example of a method that is found after traversing the prototypal chain.

It lives on Object.

prototype.

Note: The __proto__ property should not be overridden as it will break the prototype chain.

It should also never be used to read values, as accessing it is very slow.

You can read about it in detail here.

Creating SubclassesA subclass is a class that inherits properties from another class but that also has its own unique properties that override the parent class’ properties or don’t exist on the parent class.

Let’s create our first subclass:// base classfunction Loader(isLoading) { this.

isLoading = isLoading;}Loader.

prototype.

showLoader = function() { console.

log('loader visible!');}Loader.

prototype.

hideLoader = function() { console.

log('loader hidden');}// subclassfunction ProgressBarLoader(isLoading, loadedPercent) { Loader.

call(this, isLoading); this.

loadedPercent = loadedPercent || 0;}ProgressBarLoader.

prototype = Object.

create(Loader.

prototype);ProgressBarLoader.

prototype.

constructor = ProgressBarLoader;ProgressBarLoader.

prototype.

showLoadedPercent = function() { console.

log('progress %: ', this.

loadedPercent);}ProgressBarLoader.

prototype.

setPercent = function(percent) { this.

loadedPercent = percent;}var progressBarLoader = new ProgressBarLoader(false, 0);progressBarLoader.

showLoader(); // loader visibleprogressBarLoader.

hideLoader(); // loader hidden progressBarLoader.

showLoadedPercent(); // progress %: 0Lots of things are going on here.

Let’s examine them one by one:callcall is a function that helps us invoke a method with arguments and set its this context to an explicitly specified object.

This object is passed in as the first argument of call.

When we create an object of ProgressBarLoader, Loader is called in the context of ourProgressBarLoader object and the property isLoading is added to the object.

In this way, the properties of Loader are added (alternatively, inherited, borrowed) to any instance created using ProgressBarLoader.

 One thing to note here is that these properties and methods are added at the time of instantiation of the class rather than at the time of definition.

After the call statement is done executing, the loadedPercent property, which is exclusive to ProgressBarLoader, is added to the object.

Note: It is important to note that the call statement should be the first statement inside a subclass to avoid overriding of properties that exist in a subclass by the properties having the same name that exist in the parent class.

Invoking Parent Methods from SubclassConsider an example where two classes that have a parent-child relationship have the same method name, but different implementations of the same method:function Parent() {}Parent.

prototype.

printMe = function() { console.

log('This is parent class!');}function Child() { Parent.

call(this);}Child.

prototype.

printMe = function() { console.

log('This is child class!');}var child = new Child();child.

printMe(); // This is child class!Child.

prototype.

printMe is called when printMe is invoked on a Childobject.

What if we wanted to call Parent’s printMe on a Child object?.We can achieve this by using call:Parent.

prototype.

printMe.

call(child); // This is parent class!We are directly invoking Parent.

prototype.

printMe.

But it is invoked using call, which helps us in telling JavaScript that printMe has to be invoked in the context of the Child object.

This works but it is inconvenient to write Parent.

prototype.

printMe.

callevery single time we want to invoke the parent class’ method.

To fix this, let’s add a method to Child that provides a convenient API to call Parent’s printMe:Child.

prototype.

printParentMe = function() { Parent.

prototype.

printMe.

call(this);}var child = new Child();child.

printParentMe(); // This is parent class!Object.

createObject.

create creates a new object from an existing object with the new object having access to the properties of the existing object.

For example:var loader = { showLoader: function() { console.

log('loader is visible!'); }, hideLoader: function() { console.

log('loader is hidden!'); }};var progressBarLoader = Object.

create(Loader);progressBarLoader.

showLoader(); // loader is visible!progressBarLoader.

hideLoader(); // loader is hidden!So, what is Object.

create doing under the hood?.Is it copying everything from loader and adding it to progressBarLoader?.No.

It’s setting the __proto__ of progressBarLoader to loader!When we invoke progressBarLoader.

showLoader, JavaScript checks if showLoader exists on progressBarLoader.

It doesn’t, so it goes up the prototype chain using progressBarLoader‘s __proto__ and finds the method there and invokes it.

In the subclass example, Object.

create is used as follows:ProgressBarLoader.

prototype = Object.

create(Loader.

prototype);Let’s see what would have happened if this statement weren’t there:When progressBarLoader.

showLoader is invoked, JavaScript first checks for the method on progressBarLoader.

It doesn’t find it there and checks for it on the prototype of progressBarLoader.

Now, what is the prototype of progressBarLoader?.Its ProgressBarLoader and showLoader doesn’t exist on its prototype.

Therefore, we use Object.

create to add Loader.

prototype to progressBarLoader‘s __proto__.

Here’s how it looks:Now, we can add stuff to ProgressBarLoader.

prototype without affecting the Loader.

prototype’s methods that were added using Object.

create:ProgressBarLoader.

prototype.

showLoadedPercent = function() { console.

log('progress %: ', this.

loadedPercent);}ProgressBarLoader.

prototype.

setPercent = function(percent) { this.

loadedPercent = percent;}Subclass.

prototype.

constructorLet’s understand the significance of:ProgressBarLoader.

prototype.

constructor = ProgressBarLoader;Assume that this statement was not there in our example.

What would ProgressBarLoader.

prototype.

constructor point to?.Usually, when we create a function, say fn, then fn.

prototype.

constructor would point to fn itself.

But ProgressBarLoader.

prototype.

constructor points to Loader because in the statement:ProgressBarLoader.

prototype = Object.

create(Loader.

prototype);we set ProgressBarLoader.

prototype to reference Loader.

prototype and Loader.

prototype.

constructor is Loader!.Why is this a problem?.This Stack Overflow thread explains it perfectly.

Therefore, we set ProgressBarLoader.

prototype.

constructor to ProgressBarLoader.

Note: Since ProgressBarLoader is considered a child class of Loader, one could assume ProgressBarLoader.

constructor will be equal to Loader.

However, that is not the case.

It is still equal to Function just like Loader.

This is because, as we learned, the constructor property points to the function constructor and the function constructor of ProgressBarLoader is still Function.

So, in JavaScript:creating a subclass is just borrowing of methods and properties from a base class.

Only a prototypal link is created between the two classes and nothing else changes.

This is unlike many object-oriented programming languages where there is a stricter sense of inheritance between a base class and a child class.

Usage of the Word ‘Prototype’Whenever someone uses the word ‘prototype’ in a sentence, it could mean two things — the prototype keyword or __proto__.

The way to figure out which of the two is being referred to is to understand the context in which it is being used.

If we are talking about a function, the ‘prototype’ refers to the prototypekeyword.

If the subject of discussion is an object, then ‘prototype’ refers to __proto__.

Wrapping It Up!First of all, thanks for taking the time to read this!The concepts we discussed today are complex and it usually takes time to grasp them, especially for people starting out with JavaScript.

So if you still don’t feel 100% confident about them, don’t worry!.It’s normal.

It’s not your fault.

It will likely take multiple reads from multiple sources — and a bit of actual experience of writing JavaScript code — to get close to 100.

If you have any questions or feedback, drop them in the comments!.And if you feel the article helped you in any way, please show your appreciation by clapping for it!.????.

. More details

Leave a Reply