Q20 of 40 · JavaScript

How does prototypal inheritance work in JavaScript, and how does `class` relate to it?

JavaScriptMidjavascriptprototypesinheritanceclassoop

Short answer

Short answer: Every object has an internal `[[Prototype]]` reference. Property lookups traverse the chain until found or null. `class` syntax is syntactic sugar — methods are placed on `ClassName.prototype`, shared across all instances, not copied. Understanding this explains `instanceof`, `hasOwnProperty`, and prototype mutation effects.

Detail

JavaScript uses prototype-based inheritance rather than classical inheritance. Objects inherit from objects directly.

Prototype chain: When you access obj.foo, JS checks obj itself, then Object.getPrototypeOf(obj), then its prototype, up to null. This is the prototype chain lookup.

Constructor functions and .prototype: When you call new Fn(), the created object's [[Prototype]] is set to Fn.prototype. Methods on Fn.prototype are shared across all instances — not copied — which is memory-efficient.

class syntax: ES6 class desugars to constructor functions + prototype assignments. class Dog extends Animal sets Dog.prototype.__proto__ = Animal.prototype and handles the super call. The prototype chain is identical underneath.

Implications for testing: Understanding prototype chains helps debug unexpected property access — why hasOwnProperty vs in behave differently, and why adding to a constructor's prototype after instantiation still affects all existing instances.

// EXAMPLE

// Manual prototype chain
const animal = { eat() { return "eating"; } };
const dog = Object.create(animal);
dog.bark = () => "woof";

console.log(dog.eat());       // "eating" — found on animal prototype
console.log(dog.hasOwnProperty("eat"));  // false
console.log(dog.hasOwnProperty("bark")); // true
console.log(Object.getPrototypeOf(dog) === animal); // true

// class — same mechanism
class Animal {
  eat() { return "eating"; }
}
class Dog extends Animal {
  bark() { return "woof"; }
}
const fido = new Dog();
console.log(fido.eat());             // traverses prototype chain
console.log(fido instanceof Dog);    // true
console.log(fido instanceof Animal); // true

// WHAT INTERVIEWERS LOOK FOR

Understanding that `class` is sugar over prototypes. The chain traversal algorithm. Distinguishing own properties from inherited ones with `hasOwnProperty`. Bonus: noting that mutating `Dog.prototype` after instantiation affects existing instances.

// COMMON PITFALL

Thinking `class` in JavaScript copies methods to each instance like Java — methods are shared via the prototype. Mutating `Dog.prototype.bark` after creating instances affects all of them.