Before starting with prototypal inheritance let's first understand what prototype is.
All the objects in the JavaScript like
Array,Boolean,Dateetc all inherit properties and methods from their prototype.
Object is the at top of Prototype chain means all the other objects inherit their properties and methods from Object.prototype
Suppose we have Person object constructor
function Person(name, age) {
this.name = name;
this.age = age;
}Then we create objects of Person as follows
const person1 = new Person("David", 30);
const person2 = new Person("John", 35);
console.log(person1); // {name: "David", age: 30}
console.log(person2); // {name: "John", age: 35}If we want to add another property to the Person object we can add that to an individual object like this:
person1.gender = 'Male';but this will only add this property to person1 object.
console.log(person1.gender); // Male
console.log(person2.gender); // undefinedTo add the property to the Person object itself we have to add it to its prototype before creating objects so it will be available to all of its objects.
Person.prototype.gender = 'Male';
const person1 = new Person("David", 30);
const person2 = new Person("John", 35);
console.log(person1.gender); // Male
console.log(person2.gender); // MaleWe can also add methods to the Person prototype
Person.prototype.display = function() {
console.log(this.name, this.age);
};
const person1 = new Person("David", 30);
const person2 = new Person("John", 35);
person1.display(); // David 30
person2.display(); // John 35So to add any property or method to an object, we need to add it to its prototype.
If we compare the person1 and person2 display methods we will see that it returns true
console.log(person1.display === person2.display) // trueIt returns true because in memory there is only a single copy of the display function because we added the method to its prototype so it's shared by all objects.
Let's see what happens when we add it directly inside the Person constructor
function Person(name, age) {
this.name = name;
this.age = age;
this.display = function() {
console.log(this.name, this.age);
};
}
const person1 = new Person("David", 30);
const person2 = new Person("John", 35);
person1.display(); // David 30
person2.display() // John 35Now, let's compare the display methods
console.log(person1.display === person2.display) // falseNow it displays false because as we have added the method directly to the constructor function, each object created from Person will have its own copy of function so there are two copies of display function in memory here and as we create more objects, the number of copies of display function inside memory will also increase.
So it's a bad practice and it's not recommended to create methods directly inside the constructor function instead we should add them to the prototype.
Now, we have some basic knowledge of prototypes, let's understand prototypal inheritance now.
Prototypal Inheritance
Let's start with the same Person example above
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.display = function() {
console.log(this.name, this.age);
};Now, let's create Employee constructor function which will inherit the properties and methods of Person
function Employee(name, age, salary) {
Person.call(this, name, age);
this.salary = salary;
}
const emp = new Employee('Mike', 20, 4000);Here, we are using Person.call function to call the Person's constructor and pass the name and age to it
Now, let's check what emp contains
console.log(emp); // {name: "Mike", age: 20, salary: 4000}As you can see, it contains all the properties of Person plus its own properties
Now, let's call the display method using emp object.
emp.display(); // Error: emp.display is not a functionWhy do we get the error?
This is because we only mentioned inheriting properties of Person using Person.call(this, name, age)
To inherit methods also, we need to link the prototype and then create an object
Employee.prototype = Object.create(Person.prototype);
const emp = new Employee('Mike', 20, 4000);
emp.display(); // Mike 20Now, let's check the type of Employee which we can check using constructor property
console.log(emp.constructor) // Person
console.log(Employee.prototype.constructor) // PersonIt prints Person which is wrong because we know that, it should be Employee. The constructor property should always return the correct type.
Suppose, we have an array
const numbers = [1, 2, 3, 4];
console.log(typeof numbers); // "object"We get object because every array in JavaScript is an object so to get its correct type we can use constructor property that returns the correct type.
console.log(numbers.constructor) // Array
console.log(numbers.constructor === Array) // trueSo to fix the issue with Employee constructor we need to change its constructor type
Employee.prototype.constructor = Employee;
console.log(emp.constructor) // Employee
console.log(Employee.prototype.constructor) // EmployeeNow, we get the correct result.
The complete prototypal inheritance will look like this
As you can see, even for the simple prototypal inheritance we have to add a lot of extra code.
So ES6 has added class syntax which allows us to implement the same in an easy way.
As you can see, the class-based syntax is short and easy to understand when compared with prototypal inheritance.
Note: The class at the end uses the prototypal inheritance itself. It's just that, we don't need to worry about it
That's it for today. I hope you learned something new.
Don't forget to subscribe to get my weekly newsletter with amazing tips, tricks, and articles directly in your inbox here.