TL;DR
At core, Prototypical inheritance in JavaScript is a way for an object to inherit the properties and methods from other object. In JavaScript object has a special and hidden property [[Prototype]]
This property can either be null
or reference to other object, called "a prototype". This property can be accessed via __proto__
or Object.getPrototypeOf()
. When we read a property from an object and if it's missing in that object, JavaScript reaches out to it's prototype object and tries to find it there, This is what prototypical inheritance is.
const person = {
"department": "IT",
"location": "San Jose"
}
const employee = {
"name": "Shubham"
}
Object.setPrototypeOf(employee, person); // sets employee.[[Prototype]] = person
You can also use __proto__
to set or get the prototype of an object. As is generally considered the proper way to set the prototype of an object. You should always use it in favour of the deprecated Object.prototype.__proto__
accessor.
Now, if we read the property from employee
and it's missing, JavaScript engine will try to read it from it's prototype which is person
.
For instance:
alert(employee.department); //IT
alert(employee.location); //San Jose
JavaScript Prototypical Inheritance
Prototypical inheritance is a feature in JavaScript to create objects which can inherit properties or methods from other objects, Instead of class based inheritance, JavaScript uses a prototype based model.
Key Features:
In JavaScript, every object has a prototype. If you create an object using either object literal syntax or object constructor, The new object is linked with object prototype of the object constructor or Object.prototype
if nothing was specified. We can reference the object prototype using either __proto__
or [[Prototype]]
. It's recommended to use built-in method to get/set the prototype of an object. You can use Object.getPrototypeOf(obj, prototype)
and Object.setPrototypeOf()
to get/set prototype of an object.
Please note, for historical reasons, you can also use __proto__
as a getter/setter for prototype object but it's not recommended because it's outdated and deprecated in browser environments.
// Define a constructor function
function Person(name, age) {
this.name = name;
this.age = age;
}
// Add a method to the prototype
Person.prototype.sayHello = function () {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
// Create a new object using the constructor function
let john = new Person('John', 30);
// The new object has access to the methods defined on the prototype
john.sayHello(); // "Hello, my name is John and I am 30 years old."
// The prototype of the new object is the prototype of the constructor function
console.log(john.__proto__ === Person.prototype); // true
// You can also get the prototype using Object.getPrototypeOf()
console.log(Object.getPrototypeOf(john) === Person.prototype); // true
// You can set the prototype of an object using Object.setPrototypeOf()
let newProto = {
sayGoodbye: function () {
console.log(`Goodbye, my name is ${this.name}`);
},
};
Object.setPrototypeOf(john, newProto);
// Now john has access to the methods defined on the new prototype
john.sayGoodbye(); // "Goodbye, my name is John"
// But no longer has access to the methods defined on the old prototype
console.log(john.sayHello); // undefined
A prototype of an object can either be an another object or null. Any other type is ignored by JavaScript engine.
Prototype chain:
When we access a property or a method on an object, JavaScript tries to find it on the same object if it can't then it tries to find it in object's prototype and if still cannot find it, it will look into object prototype's prototype, and so on, until it cannot finds it in the chain or reaches at the end of it (i.e. null).
Creating a prototype:
Object Constructor: When a function is used as a constructor with new keyword, the new object's prototype is set to the constructor's prototype property.
function Circle(radius) { this.radius = radius; } Circle.prototype.getArea = function() { return Math.PI * Math.pow(this.radius, 2); }; const circle = new Circle(5); circle.getArea(); // `78.53981633974483` // The constructor function Circle's prototype is assigned to // circle object. console.log(Object.getPrototypeOf(circle) === Circle.prototype); // true
Object.create(): This method provides a way to create an object with given prototype and properties. This also allow you to create an orphan objects (no pun intended) without any prototype assigned using,
Object.create(null)
. This should return the literal empty object with prototype set to null. This method provides a straight forward way to setup a prototypical inheritance.const car = { brand: "BMW", year: 2024, FWD: "yes" } const obj = Object.create(null); console.log(Object.getPrototypeOf(obj)); // null const X1 = Object.create(car); X1.model = 'BMW X1 series'; // Property model is set on X1 not car. X1.color = "Black"; console.log(X1.brand); //BMW
That's a wrap! Hope you have enjoyed learning these concepts as much as I did while writing. Do follow or subscribe to my newsletter for more content like this.