Prototypes, Prototype Chain, and Class Inheritance
JavaScript uses prototypal inheritance where objects hold an internal [[Prototype]] reference to another object. Property lookups traverse up this prototype chain until found or null is reached.
Why it matters in interviews
Visual & Interactive Explanation
1. Access myObj.toString()
V8 engine checks own properties of myObj instance
2. Not found on instance
Traverses to myObj.__proto__ (e.g. Array.prototype)
3. Check Array.prototype
Array.prototype searched. Not found -> moves to Array.prototype.__proto__
4. Found on Object.prototype
Found Object.prototype.toString. Method invoked with this = myObj
5. Chain terminator
If not found on Object.prototype, lookup checks null and returns undefined
Code Examples & Implementation
// ❌ BAD: Re-creates getName function for every instance (10,000 users = 10,000 function objects)
function UserBad(name: string) {
this.name = name;
this.getName = function() { return this.name; };
}
// ✅ GOOD: Shares single function reference on User.prototype across all instances
function UserGood(name: string) {
this.name = name;
}
UserGood.prototype.getName = function() {
return this.name;
};
// ES6 Class Equivalent (desugars directly to UserGood.prototype.getName)
class UserClass {
name: string;
constructor(name: string) {
this.name = name;
}
getName() {
return this.name;
}
}
// Prototypal Subclassing with Object.create
function Admin(name: string, permissions: string[]) {
UserGood.call(this, name); // Super constructor call
this.permissions = permissions;
}
Admin.prototype = Object.create(UserGood.prototype);
Admin.prototype.constructor = Admin;Interview-Ready Answers
Every JavaScript object has an internal [[Prototype]] link. When accessing a property, the V8 engine checks the instance first, then its prototype, and continues up the chain until null.
Official Documentation & Specifications
Follow-up Questions & Deep Dives
🎯 Code Output — What Does This Print?
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return this.name + " makes a sound";
};
const dog = new Animal("Rex");
console.log(dog.speak());
console.log(dog.hasOwnProperty("speak"));
console.log(dog.hasOwnProperty("name"));function A() {}
function B() {}
B.prototype = Object.create(A.prototype);
const b = new B();
console.log(b instanceof B);
console.log(b instanceof A);
console.log(b instanceof Object);const parent = { x: 1 };
const child = Object.create(parent);
child.y = 2;
console.log(child.x);
console.log(child.y);
console.log("x" in child);
console.log(child.hasOwnProperty("x"));function Foo() {}
Foo.prototype.x = 10;
const a = new Foo();
const b = new Foo();
a.x = 20;
console.log(a.x);
console.log(b.x);
delete a.x;
console.log(a.x);Common Mistakes & Anti-Patterns
- Defining methods inside constructor functions or React component render functions instead of prototype/memoized handlers.
- Modifying native prototypes like Array.prototype (prototype mutation breaks engine optimizations and third-party code).
- Confusing the function property 'MyFunc.prototype' with the object link 'obj.__proto__'.
Real-World Architectural Scenario
A high-frequency financial grid instantiates 50,000 row model objects. Memory usage spiked to 300MB. How do prototypes solve this?
Rate Your Readiness
Rate how comfortably you can explain this in an interview to update your global readiness gauge: