Skip to main content

Inheritance is a core OOP concept that most software developers should be familiar with. Simply put, it is the ability for one class to reuse (inherit) the properties of another class. It is present in languages like C++, Java, Python, C# and of course Javascript. However, under the hood, inheritance in Javascript looks quite different when compared to the previously mentioned languages. In this blog I will break down the concept of inheritance in Javascript and individually explain each chunk in the hopes of painting a clearer picture of how it works.

Everything in Javascript is an object

Prototypal inheritance chains

Well, not exactly everything in Javascript is an object. Everything apart from the primitive types (null , undefined , strings, numbers, boolean, and symbols) is an object in Javascript. This also includes arrays and functions. To test this we can use the __proto__ property. The __proto__ property is a pointer that points to the prototype of the object from which the current object derives its properties. Additionally, the prototype is a special enumerable object that is incorporated into every function and object and contains the methods that they can share. In the browser, if we create an empty array and call its __proto__ property, we get the following:

Base Array

We receive an array with quite a few functions, some of which should be familiar to us. This is the base array from which all newly created arrays are derived from. The new arrays inherit all of these properties from the base array and are able to use them when needed. If we call the __proto__ property on this base array we will get the following:

This time we received the base object along with some familiar methods again. This is the object from which all non primitive types are derived from. To observe this again we can repeat the same steps with a function. Going up the prototype chain once will give us the base Function. Doing it twice will give us the base object again. Similarly if we create an object and go up its prototype chain we will receive the base object.

This is the power of prototypal inheritance. All of the non primitive instances that we use while writing Javascript start from the base object. They then follow down the chain inheriting all of the properties until they reach their own initialisation. This is the difference between other object oriented languages and Javascript. In other languages inheritance occurs through classes. In Javascript the classes are themselves objects that are able to achieve inheritance through the use of prototypes. But why is this important? Let’s answer this question with an example.

Prototypal inheritance in action

const cat = {
    name: "Tom",
    purr: function() {
        console.log(this.name + " is purring!");
    },
}

const cat2 = Object.create(cat);
cat2.name = "Tony";

function printObjectProperties(object) {
    console.log( object.name + "'s properties are:")
    for (let prop in object) {
        if(object.hasOwnProperty(prop)) {
            console.log(prop);
        };
    }
}
cat.purr();
cat2.purr();
printObjectProperties(cat);
printObjectProperties(cat2);
console.log(cat2.__proto__);

// Output:
//
// Tom is purring!
// Tony is purring!
// Tom's properties are:
// name
// purr
// Tony's properties are:
// name

First we create a cat object. Then we create a second cat object derived from the first one. Finally, we call each of their purr methods and then we log all their properties. The first thing we notice is that the second cat object does not have the purr method, but it is still able to use it. This is achieved through prototypal inheritance. Under the hood, when the second object calls the purr method, the engine checks if the object has this method. Then, after it does not find this method in the scope of this object it moves up the prototype chain. It reaches the first object and locates the purr method. We can see this by calling the __proto__ property for the second object. In the screenshot below, we see that it points to the first object.

Interestingly enough, this code block contains an example that goes even deeper along the prototype chain. If we take a look inside the printObjectProperties function we notice the hasOwnProperty method. This method is not a property of neither the first nor second object. Instead it’s a property of the base object. When the engine executed the hasOwnProperty method for the first object, it went up its prototype chain to the base object. Similarly, when it executed the same method for the second object it went up the prototype chain to the first object and then it went up the chain once more to the base object. With this we can see the efficiency and importance of prototypal inheritance. These methods only need to be declared once and were then able to be accessed from all of the derived objects down the chain.

Another advantage of prototypal inheritance is adding properties to prototypes after they have been created. We can see this in the next code example. We create a date object, we access the prototype of the base Date object and we add a custom method to it. Later, we call the newly created method from the date object and we can see that it executed as we intended.

const date = new Date('2022-11-28');

Date.prototype.lastYear = function() {
    return this.getFullYear() - 1;
}

console.log(date.lastYear());

//Output:
//
//2021

Conclusion

To recap, mostly everything in Javascript is an object derived from one base object. All objects in javascript have a pointer that points to the prototype of the object above it in the prototype chain. At the very top of the prototype chain is the base object which contains all of the default object methods. Whenever we call a method or a property on an object, Javascript checks if this property or method exists within the object itself. If it does not find it, it begins ascending the prototype chain until it locates the method or property and if it does not find it, it will return null.

The advantage of prototypal inheritance are the ability to manage memory by only having certain methods and properties declared once. These methods and properties can later be accessed by other child objects by ascending up their prototype chains. Additionally, we can directly manipulate the prototype of base objects and add additional functionality which can later be accessed by objects down the prototype chain.

Leave a Reply


The reCAPTCHA verification period has expired. Please reload the page.