JavaScript doesn't have classical inheritance — it has prototypal inheritance. Understanding the prototype chain is essential for interviews and debugging.
The Prototype Chain
Every object has an internal [[Prototype]] link. When you access a property, JS walks up the chain until it finds it or reaches null.
const animal = { eat() { return "eating"; } };
const dog = Object.create(animal);
dog.bark = function() { return "woof"; };
dog.bark(); // "woof" — found on dog
dog.eat(); // "eating" — found on animal (prototype)
dog.toString(); // found on Object.prototypeConstructor Functions
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`;
};
const rahul = new Person("Rahul");
rahul.greet(); // "Hi, I'm Rahul"
// Chain: rahul → Person.prototype → Object.prototype → nullES6 Classes (Syntactic Sugar)
class Person {
constructor(name) { this.name = name; }
greet() { return `Hi, I'm ${this.name}`; }
}
class Developer extends Person {
constructor(name, lang) {
super(name);
this.language = lang;
}
}
// Still prototypal under the hood!Common Gotchas
Object.create(null)creates an object with NO prototype — no toString, no hasOwnProperty. Used for pure dictionaries.hasOwnPropertyvsin:inchecks the chain,hasOwnPropertychecks only the object- Modifying
Array.prototypeorObject.prototypeaffects ALL instances — never do this in production __proto__is deprecated — useObject.getPrototypeOf()andObject.setPrototypeOf()
Performance
V8 optimizes prototype lookups with hidden classes and inline caches. Long prototype chains (5+) can degrade performance. Keep inheritance shallow.