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 in myObject
  • if the Javascript engine can't find it there, the Javascript engine looks into the prototype object of myObject for toString() 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().