In JavaScript, Prototypal Inheritance is the core mechanism that allows objects to inherit properties and methods from other objects. Unlike classical inheritance (found in Java or C++), which uses classes as blueprints to create instances, JavaScript objects inherit directly from other objects via a link called the Prototype Chain.

1. The Prototype Chain Mechanics

When you attempt to access a property or a method of an object, JavaScript follows a specific lookup delegation process:

  • Object Instance: It first checks if the property exists directly on the object.
  • The Prototype: If not found, it moves to the object’s [[Prototype]].
  • The Chain: It continues moving up the chain of prototypes.
  • End of Chain: If it reaches Object.prototype and the property is still missing, it looks at null and finally returns undefined.

Example of Delegation

JavaScript

const animal = {
  eats: true,
  walk() {
    console.log("Animal walks");
  }
};

const rabbit = Object.create(animal); // rabbit inherits from animal
rabbit.jumps = true;

console.log(rabbit.eats); // true (found in animal)
rabbit.walk();            // "Animal walks" (found in animal)

2. Implementing Inheritance: Three Primary Ways

A. Constructor Function Pattern (The Traditional Way)

This was the standard before 2015. It involves “stealing” properties from a parent constructor and linking prototype objects manually.

JavaScript

function Human(name) {
  this.name = name;
  this.arms = 2;
}

Human.prototype.breathe = function() {
  console.log(`${this.name} is breathing...`);
};

function Developer(name, language) {
  // 1. Constructor Stealing: Call the parent constructor with 'this'
  Human.call(this, name); 
  this.language = language;
}

// 2. Prototype Linking: Set the Developer's prototype to a new object 
// that inherits from Human.prototype
Developer.prototype = Object.create(Human.prototype);

// 3. Constructor Repair: Reset the constructor property back to Developer
Developer.prototype.constructor = Developer;

const dev = new Developer("Leo", "JavaScript");
dev.breathe(); // Inherited from Human.prototype

While ES6 introduced the class and extends keywords, it is essential to understand that these are “syntactic sugar” over the underlying prototypal system.

B. Object.create() (The Pure Way)

If you don’t need a constructor function, you can create inheritance directly between two existing objects. This is the cleanest representation of the prototypal philosophy.

JavaScript

const vehicle = {
  drive() { console.log("Moving..."); }
};

const car = Object.create(vehicle);
car.wheels = 4;

car.drive(); // "Moving..." (Inherited)

C. ES6 Classes (The Modern Way)

The class and extends keywords introduced in 2015 provide a cleaner syntax that mirrors classical languages but operates entirely on the prototype chain under the hood.

JavaScript

class Vehicle {
  constructor(fuel) { this.fuel = fuel; }
  refuel() { console.log("Refueling..."); }
}

class ElectricCar extends Vehicle {
  constructor(fuel, battery) {
    super(fuel); // Reference the parent constructor
    this.battery = battery;
  }
}

3. Method Overriding and Shadowing

Inheritance allows an object to provide its own implementation of a method found in the prototype. This is known as Property Shadowing. The engine finds the property on the instance first and stops the search, never reaching the prototype’s version.

JavaScript

const parent = {
  greet() { return "Hello from Parent"; }
};

const child = Object.create(parent);
child.greet = function() { return "Hello from Child"; };

console.log(child.greet()); // "Hello from Child"

4. Property Shadowing and “Own” Properties

When a child object defines a property with the same name as one in its prototype chain, it shadows the inherited property. The engine finds the property on the local object first and stops searching.

  • hasOwnProperty() / Object.hasOwn(): Used to distinguish between properties physically located on the instance versus those inherited via the chain.

JavaScript

const parent = { name: 'Parent' };
const child = Object.create(parent);
child.name = 'Child'; 

console.log(child.name); // 'Child' (Shadowed)
console.log(Object.hasOwn(child, 'name')); // true

Categorized in:

Javascript,