Gyaan

Prototypal Inheritance

intermediate prototype inheritance prototype-chain __proto__

JavaScript doesn’t have classical inheritance like Java or C++. Instead, it uses prototypal inheritance — objects inherit directly from other objects. Every object has a hidden link to another object called its prototype.

Every object has a [[Prototype]]

When we create an object, JavaScript secretly links it to another object — its prototype. We can access this link using Object.getPrototypeOf(obj) or the older __proto__ property.

const user = { name: "Manish" };

console.log(Object.getPrototypeOf(user)); // Object.prototype
console.log(user.__proto__);               // same thing (older way)
console.log(user.__proto__ === Object.prototype); // true

The Prototype Chain

When we try to access a property on an object, JavaScript first looks at the object itself. If it doesn’t find it there, it goes up to the prototype. If it’s not there either, it goes to the prototype’s prototype, and so on — until it hits null.

Prototype Chain Lookup
dog instance
{ name: "Buddy", breed: "Lab" }
Step 1: look here first
↓ __proto__
Animal.prototype
{ speak() { ... } }
Step 2: if not found, check here
↓ __proto__
Object.prototype
{ toString(), hasOwnProperty(), ... }
Step 3: the base prototype
↓ __proto__
null
End of the chain — property not found → undefined
function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

const dog = new Animal("Buddy");
dog.breed = "Lab";

dog.breed;           // "Lab" — found on dog itself
dog.speak();         // found on Animal.prototype
dog.toString();      // found on Object.prototype
dog.randomProp;      // undefined — not found anywhere in the chain

Object.create() for Prototypal Inheritance

Object.create() creates a new object and sets its prototype to whatever we pass in:

const animal = {
  speak() {
    console.log(`${this.name} makes a sound`);
  }
};

const dog = Object.create(animal);
dog.name = "Buddy";
dog.speak(); // "Buddy makes a sound"

console.log(Object.getPrototypeOf(dog) === animal); // true

Constructor Functions and prototype

When we use new with a function, the created object’s __proto__ is set to the constructor’s prototype property.

function Person(name) {
  this.name = name;
}
Person.prototype.greet = function() {
  console.log(`Hi, I'm ${this.name}`);
};

const manish = new Person("Manish");
manish.greet(); // "Hi, I'm Manish"

// The chain:
// manish.__proto__ === Person.prototype  → true
// Person.prototype.__proto__ === Object.prototype  → true

Methods defined on prototype are shared across all instances — they exist only once in memory, not copied to each instance.

hasOwnProperty() vs in operator

When checking if a property exists, there’s an important difference:

  • hasOwnProperty() — only checks the object itself, NOT the prototype chain
  • in operator — checks the object AND the entire prototype chain
function Car(model) {
  this.model = model;
}
Car.prototype.wheels = 4;

const car = new Car("Civic");

car.hasOwnProperty("model");   // true — own property
car.hasOwnProperty("wheels");  // false — it's on the prototype

"model" in car;   // true — found on object
"wheels" in car;  // true — found on prototype chain

Use hasOwnProperty() when we want to check only the object’s own properties (like when iterating with for...in and we want to skip inherited ones).

for (const key in car) {
  if (car.hasOwnProperty(key)) {
    console.log(key); // only "model", not "wheels"
  }
}

In simple language, JavaScript doesn’t copy properties from parent to child. Instead, it creates a chain of links between objects. When we access a property, JS walks up this chain until it finds it (or reaches the end). This is prototypal inheritance — and it’s how everything in JavaScript works under the hood, including classes.