In programming, inheritance refers to passing down characteristics from a parent to a child so that a new piece of code can reuse and build upon the features of an existing one. JavaScript implements inheritance by using objects. Each object has an internal link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype and acts as the final link in this prototype chain.
Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.
When you try to access a property of an object: if the property can't be found in the object itself, the prototype is searched for the property. If the property still can't be found, then the prototype's prototype is searched, and so on until either the property is found, or the end of the chain is reached, in which case undefined is returned.
So when we call myObject.toString(), the Javascript engine follows the prototype chain to resolve the method:
- looks for
toString()method inmyObject - if the Javascript engine can't find it there, the Javascript engine looks into the prototype object of
myObjectfortoString()method - if the Javascript engine finds it there, the Javascript engine calls the
toString()method.
In JavaScript, __proto__ and prototype are two related but distinct concepts that are often confused with each other.
__proto__ (also called the Dunder Proto or Double Underscore Prototype) is a property of an object that points to its prototype. This property is used internally by the JavaScript engine to search for properties and methods on an object's prototype chain.
The __proto__ is not part of the ECMAScript standard, but is supported by browsers.
Object.getPrototypeOf() and Object.setPrototypeOf() are the modern ways of getting access to and setting an object's prototype.
Let's create an object literal:
const myObject = {
name: "John Doe",
greet() {
console.log(`Hello ${this.name}`);
},
};
myObject.greet(); // Hello John Doe
myObject.__proto__ // Object { }
Object.getPrototypeOf(myObject); // Object { }
Object.prototype is the most basic prototype, that all objects have by default. The prototype of Object.prototype is null, so it's at the end of the prototype chain.
The prototype of an object is not always Object.prototype. For example:
const myDate = new Date();
let object = myDate;
do {
object = Object.getPrototypeOf(object);
console.log(object);
} while (object);
// Date.prototype
// Object { }
// null
prototype is a built-in property when you create an object from a constructor function. This is like a blueprint for all the objects created from that constructor function. It defines the shared properties and methods that all instances of that object will have.
Let's create a constructor function:
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getArea = function() {
return Math.PI * Math.pow(this.radius, 2);
};
const circle1 = new Circle(5);
circle1.getArea(); // 78.53981633974483
const circle2 = new Circle(6);
circle2.getArea(); // 113.09733552923255
console.log(circle1.__proto__ === Circle.prototype); // true
console.log(circle2.__proto__ === Circle.prototype); // true
In the code above, the getArea method is contained in an object called Circle.prototype. When a new Circle instance is created, its __proto__ property is set to Circle.prototype.
circle1.getCircumference = function () {
return Math.PI * 2 * this.radius;
}
circle1.getCircumference(); // 31.41592653589793
circle2.getCircumference(); // Uncaught TypeError: circle2.getCircumference is not a function
In the code above, the getCircumference() method is added to only circle1 object and not on Circle.prototype or circle2.
Here we are comparing the __proto__ (which is the prototype from which the object was created), with the prototype (a property that only exists in constructor functions).
const fn = () => {};
fn.__proto__ === Function.prototype; // Output: true
Every function has a prototype property that points to the Function.prototype object. fn is an anonymous function created using the arrow function syntax. This means that fn inherits properties and methods from Function.prototype. For example, fn can use methods like call(), apply(), and bind() because they are defined on Function.prototype.
const fn = () => {};
fn.__proto__ === new Function().__proto__ // Output: true
fn is an anonymous function created using the arrow function syntax. new Function() creates a new function object using the Function constructor. The __proto__ property of fn points to the same object as the __proto__ property of the newly created function object using new Function().
const arr = [];
arr.__proto__ === Array.prototype; // Output: true
Every array in JavaScript has a prototype property that points to the Array.prototype object. arr is an array created using the array literal syntax []. This means that arr inherits properties and methods from Array.prototype, such as push(), pop(), and forEach().
const arr = [];
arr.__proto__ === new Array().__proto__; // Output: true
arr is an array created using the array literal syntax []. new Array() creates a new array object using the Array constructor. The __proto__ property of arr points to the same object as the __proto__ property of the newly created array object using new Array().
const obj = {};
obj.__proto__ === Object.prototype; // Output: true
Every object in JavaScript has a prototype property that points to the Object.prototype object. obj is an object created using the object literal syntax {}. This means that obj inherits properties and methods from Object.prototype, such as toString() and hasOwnProperty().
const obj = {};
obj.__proto__ === new Object().__proto__; // Output: true
obj is an object created using the object literal syntax {}. new Object() creates a new object using the Object constructor. The __proto__ property of obj points to the same object as the __proto__ property of the newly created object using new Object().
const str = 'Hello';
str.__proto__ === String.prototype; // Output: true
Strings in Javascript have a prototype property that points to the String.prototype object. str is a string created using the string literal syntax 'Hello'. This means that str inherits properties and methods from String.prototype, such as toUpperCase() and substr().
const str = 'Hello';
str.__proto__ === String.prototype; // Output: true
str is a string created using the string literal syntax 'Hello'. new String() creates a new string object using the String constructor. The __proto__ property of str points to the same object as the __proto__ property of the newly created string object using new String().
const num = 123;
num.__proto__ === Number.prototype; // Output: true
Numbers in JavaScript have a prototype property that points to the Number.prototype object. num is a number created using the number literal syntax 123. This means that num inherits properties and methods from Number.prototype, such as toFixed() and toExponential().
const num = 123;
num.__proto__ === new Number().__proto__; // Output: true
num is a number created using the number literal syntax 123. new Number() creates a new number object using the Number constructor. The __proto__ property of num points to the same object as the __proto__ property of the newly created number object using new Number().
const bool = true;
bool.__proto__ === Boolean.prototype; // Output: true
Booleans in JavaScript have a prototype property that points to the Boolean.prototype object. bool is a boolean created using the boolean literal syntax true. This means that bool inherits properties and methods from Boolean.prototype, such as toString() and valueOf().
const bool = true;
bool.__proto__ === new Boolean().__proto__; // Output: true
bool is a boolean created using the boolean literal syntax true. new Boolean() creates a new boolean object using the Boolean constructor. The __proto__ property of bool points to the same object as the __proto__ property of the newly created boolean object using new Boolean().


