JavaScript Classes, Inheritance, and Prototype Chaining (ES5 and ES6 Way)

Understanding and implementing object-oriented programming

Kunal Tandon
Developer’s Arena
5 min readAug 31, 2019

--

A JavaScript Class (ES6)

One can relate a class in JavaScript to a class in an object-oriented programming language. A class might look something like:

As a programmer, we simply create instances of the class as:

The class object gets logged as in the image above. See how an instance created for a class is represented internally with prototypes and the object’s key-value pairs.

Classes in ES5

Converting a class to ES5

The user instance we’ve just seen is represented by the prototypes and object’s key-value pairs which is the ES5 syntax. So, we can clearly say that classes are just syntactical sugar over ES5 code.

Consider the scenario if you had to write the same code in ES5, without any syntactical sugar. We can use an object creation pattern here.

The code we have written above can be written in ES5 using the following constructor function:

As you can see, we get a similar output in the console as we get when creating an instance from a class.

__proto__ Inside __proto__

Prototype chaining

Did you notice that we have a __proto__ inside the __proto__?

That’s prototype chaining.

In JavaScript, every object has a prototype and we also know that the prototype of an object is also an object, thus creating nesting of prototypes.

So, JavaScript uses a similar concept for creating an inheritance by chaining multiple instances to prototypes and creating nested prototypes.

For example, the object shown in the above image is the User object. We can assign the User.prototype.prototype to be an instance of the Person class. Thus creating an inheritance by chaining of the prototypes.

I will explain this in detail with the help of an example later in this article.

Objects Created With Classes (ES6) vs. Objects Created With Constructor Functions (ES5)

Are they exactly the same?

Although they seem to be the same, upon expanding the inner __proto__, we get to see the difference between the two.

Upon expanding the __proto__ for the instance created with the class syntax, we get nothing in the inner __proto__ object.

Instance created with Class

On the other hand, expanding the inner __proto__ for the instance created with the constructor function gives the result as:

Instance created with constructor function

This means the instance created by the ES5 constructor function is inheriting from JavaScript’s object while the instance created with the class syntax is not inheriting any of the properties from JavaScript’s object class.

With classes, we get no inheritance by default and we get a pure object assigned to the inner __proto__ property of the User object’s prototype.

We can also do that by explicitly modifying the inner __proto__ property.

Object.create(null) creates a pure object for us.

Inheritance

The ES6 way — classes

Implementing a simple inheritance in ES6 would look like the example below.

This will log the user as:

On the outer prototype, we get the functions of User (printUser function) and on the inner prototype, we get the functions of Person (printPerson function).

We get the inheritance in action using prototype chaining, but with a syntactical sugar.

Inheritance — the ES5 way

While classes are just syntactical sugar over ES5, we must know how actually inheritance is implemented in ES5.

The above inheritance example using classes can be represented in ES5 using the following syntax:

In the above code, we majorly need to understand two things:

  1. The __extends function.
  2. Person.call(this).

The __extends function takes two objects, the parent object, and the child object, and sets the prototype for the child.prototype to the instance of the parent object.

Person.call(this) calls the Person function with custom this context. Calling the Person function with custom this context includes the properties for the Person object in the User object.

Now, if we try to create the instance of the User class, we will get:

We get the same object as we received while creating an instance of the child class.

instanceof operator

For the instance created, there are properties of both User and Person. So the following two statements will return true.

--

--