Understanding Prototypal Inheritance in JS

Everything you need to understand prototypes, prototypical inheritance and prototype chain in JavaScript

I have been working with JavaScript for almost two years now, replacing a jQuery based UI with React for one of our products at Novelist. I like knowing the underbelly of the tool I am using so that I can use it more efficiently. It was quite evident from the beginning of my JS journey that understanding prototype in JavaScript was essential in understanding how the language worked. So I set forth in this venture to understand what exactly a prototype is and how we can leverage it. To understand what a prototype or prototypical inheritance is, we have to first understand how functions work in JS.

Functions in JavaScript

Functions in JavaScript are driven by the two internal methods [[Call]] and [[Construct]]. Any object with a [[Call]] method is called a function, and any function that additionally has a [[Construct]] method is called a constructor function. The [[Call]] method determines what happens when you invoke an object as a function, e.g. foo(args) , while [[Construct]] determines what happens when you invoke it as a new expression, i.e. new foo(args) . Every constructor function also has an internal [[Call]] method.

Classes are actually objects created using the constructor functions.

An important thing to realize, specially for people used to Java/C#/C++, is that there are no classes in JavaScript. Classes are actually objects created using the constructor functions. You can create instances of an object using constructor functions. In this regard, they work the same way as your Java or C# object creation. Example of a constructor function and their instantiation:

function Student(firstName, lastName) {

this.firstName = firstName;

this.lastName = lastName;

this.getName = () => `${this.firstName} ${this.lastName}`;

} let student1 = new Student("Albert","Einstein");

let student2 = new Student("Isaac", "Newton");

Prototypes

Now to the good part. Every constructor function has a property called ‘prototype’ which points to a Prototype object that is created when the function is declared. I still haven’t figured out exactly how the Prototype object is created, but let us keep that in a black box for now.

Every constructor function has a property called ‘prototype’ which points to a Prototype object that is created when the function is declared.

Since there are no classes in JavaScript, how do you create methods and properties that can be shared among instances? You do it via the prototype property i.e. you attach it to the Prototype object. This is call prototypical inheritance. In the above example, firstName, lastName and getName are created uniquely and stored on each instance of Student object. When we create instances of the Student object, each instance will have its own firstName, lastName and getName property. Now let’s add a method that will be shared by all instances:

Student.prototype.printName = () => console.log(this.getName());

Now, both student1 and student2 will share the printName() function, since it was attached to Student.prototype and they were created by the Student() constructor function. Every instance created by Student() will share printName(). But how? Great question!

Each instance created by a constructor function has an internal ‘__proto__’ property that points to its constructor functions ‘prototype’ property. It’s confusing, I know. It took me some time to get that ‘prototype’ and ‘__proto__’ property are not the same. Yes, they will usually point to the same Prototype object, but not always. We will see that in a bit, but first let’s visualize the relationship:

Relationship between prototype and __proto__

When looking for a property, JavaScript first looks if object instance has it or not, if not, it goes to the Prototype object via the ‘__proto__’ property. This is called the prototype chain. JavaScript will go all the way up until Object.prototype and will return undefined if it’s not found there.

__proto__ vs prototype

I promised that I will talk about the difference between the ‘prototype’ and ‘__proto__’ property. As I said, ‘prototype’ property is found in constructor functions that points to the Prototype object of that function and ‘__proto__’ property is found both on constructor functions and their instances and points to the Prototype objects of the functions that created them. It sounds like they should always be same, right? Let’s look at an example where that’s not the case. I find the diagram below really helpful:

Image from http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

As you can see, Foo’s ‘__proto__’ and ‘prototype’ properties point to different things. Foo is a function and therefore created by the ‘Function’ constructor function (internal to JavaScript). So the ‘__proto__’ property points to Function’s Prototype Object. But Foo’s ‘prototype’ property points to Foo’s Prototype object.

How does ES6 class syntax relate to prototypes?

As before, each class in ES6 consists of a constructor function and a prototype object which refer to each other via the prototype property. However, the order of definition of the two is reversed. With an old style class, you define the constructor function, and the prototype object is created for you. With a new style class, the body of the class definition becomes the contents of the prototype object (except for static methods), and among them, you define a constructor. The end result is the same either way.

Conclusion

I hope this helps you understand prototypes in JavaScript (have I said prototype enough?) To be honest, I will probably be reading this in a couple of months to refresh my memory. But I really enjoy doing such researches!