Prototypes

Authors

OOP

In classical OOP , class can be used to create objects which are also called instances and this process is called instantiation .

So how does OOP works in JavaScript ???

Well , in JavaScript we have something called prototypes and all object in javascript are linked to a certain prototype object . The prototype object contains methods and properties that all the objects linked to that prototype can access and use. This behaviour is called Prototypal Inheritance .

Objects inherit methods and properties from the prototype which is why this mechanism is called Prototypal Inheritance .

const num = [1, 2, 3]; num.map((n) => n * 2);

When we go to MDN to check documentation for any array method , we see that it is actually called Array.prototype . Well Array.prototype is the prototype object of all the arrays that we create in javascript .

This prototype object contains all the array methods including map , so this is where they are actually defined . So in a sense our array inherit the map method .

How do we create prototypes ? And How do we link objects to prototypes ? How can we create new objects , without having classes ?

Well in javascript we have actually three different ways of doing all this -

  • Constructor functions
  • ES6 classes
  • Object.create()

Lets create a constructor function for a person -

'use strict'; const Person = function (firstName, birthYear) { this.firstName = firstName; this.birthYear = birthYear; }; const sumit = new Person('Sumit', 1997); const jack = new Person('Jack', 1998); console.log(sumit, jack);

You can use npx jsnotepad server command to run these code directly in your browser

The basic difference between the constructor function and normal function is that we call the constructor function using new keyword .

When we call the constructor function using new , behind the scenes , there happen four steps -

  • A new empty object { } is created .
  • Function is called and in this call the this keyword will be set to the newly created object .
  • Newly created object is linked to prototype .
  • Function automatically returns the object.

In this example , after the second step we set properties to the newly created object using this keyword . So by the end of the function , the this keyword has two new properties. In the last step the created object is automatically returned from the function .

Therefore sumit object will have two properties firstName and birthYear and we can access them using sumit.firstName and sumit.birthYear .

Through this constructor function we can create as many objects as we want .

Constructor functions have been used since the beginning of JavaScript to simulate classes .

Let quickly check something --

const martha = 'martha'; console.log(jack instanceof Person); // Returns true console.log(martha instanceof Person); //Returns false

This is because jack is created by the Person constructor function .

OK,we have added properties but what if we wanted to add a methods to our objects ???

Just like we added properties we can also ofcourse add methods .

'use strict'; const Person = function (firstName, birthYear) { this.firstName = firstName; this.birthYear = birthYear; // Never do this this.calcAge = function () { console.log(2021 - this.birthYear); }; };

We should never do this , because imagine if we have thousands of objects created using this constructor function , then what would happen is that each of this object will carry around this function . In simple words thousand objects will have thousand copy of the function .

Should we not create function at all ? What is the work around ??

To Solve this problem we are going to use Prototypes and Prototypal Inheritance .

Prototypes

So first each and every function automatically has a property called prototype . Now every object that's created by a certain constructor function will get access to all the methods and properties that we define on constructor prototype property.

Person.prototype.calcAge = function () { console.log(2021 - this.birthYear); }; console.log(Person.prototype);

This prototype object will have the calcAge function and now every object that is created by Person constructor function will have access to calcAge function .

Now we should be able to do this -- sumit.calcAge() .We can use this method on sumit object even though it is not really on the object itself .

Let quickly check something -

console.log(sumit.__proto__); // This is the prototype of sumit object . console.log(sumit.__proto__ === Person.prototype); //returns true console.log(Person.prototype.isPrototypeOf(sumit)); //returns true

As we see Person.prototype is not a prototype of Person but it is prototype of all objects created by the constructor function .

Whats going on ? Where did the proto property came from ???

Well , lets scroll to step no. 3 of object creation using new . In this step we link the new object to prototype of Constructor function .

We can also set properties on the prototype , not just methods -

Person.prototype.species = 'Homo Sapiens'; console.log(jack.hasOwnProperty('firstName')); //returns true console.log(jack.hasOwnProperty('species')); //returns false

We see this behaviour as species property is not really inside the jack object but in the prototype of Person .

Next Blog Post will be a continuation of this where we will discuss about prototypal inheritance ...