Prototypes & Prototype Chain
JavaScript's real inheritance system — how objects inherit from other objects
Last updated on
Prototypes are the most important interview topic in JavaScript. The class syntax is just sugar — under the hood, everything is prototypes.
"Prototype tells WHERE methods are searched."
What is a Prototype?
Every JavaScript object has a hidden internal property called [[Prototype]] (accessible via __proto__ or Object.getPrototypeOf()). When you access a property that doesn't exist on an object, JavaScript looks up the prototype chain.
const user = { name: "Shiva" };
// user doesn't have toString(), but it works:
user.toString(); // "[object Object]"
// Because JavaScript found it on Object.prototype:
Object.getPrototypeOf(user) === Object.prototype; // trueThe Prototype Chain
user (own property: name)
↓ __proto__
Object.prototype (toString, hasOwnProperty, valueOf, etc.)
↓ __proto__
null (end of the chain)const arr = [1, 2, 3];
// arr → Array.prototype → Object.prototype → null
arr.push(4); // found on Array.prototype
arr.toString(); // found on Object.prototype
arr.nonExistent; // undefined (searched all the way to null)__proto__ vs prototype
This is the most confusing part. Here's the clear distinction:
__proto__ | prototype | |
|---|---|---|
| Exists on | Every object | Only functions |
| What it is | Link to parent object | Template for instances created with new |
| Usage | obj.__proto__ | Function.prototype |
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return `Hi, I'm ${this.name}`;
};
const shiva = new Person("Shiva");
// shiva.__proto__ === Person.prototype
// Person.prototype.__proto__ === Object.prototype
// Object.prototype.__proto__ === nullshiva Person.prototype Object.prototype
{ name: "Shiva" } → { greet: fn } → { toString: fn, ... } → null
__proto__ __proto__ __proto__Creating Prototypal Inheritance
Using Object.create()
const animal = {
eat() {
return `${this.name} is eating`;
}
};
const dog = Object.create(animal); // dog's prototype = animal
dog.name = "Rex";
dog.bark = function () {
return "Woof!";
};
dog.eat(); // "Rex is eating" — found on animal (prototype)
dog.bark(); // "Woof!" — found on dog (own property)Using Constructor Functions
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function () {
return `${this.name} is eating`;
};
function Dog(name, breed) {
Animal.call(this, name); // call parent constructor
this.breed = breed;
}
// Set up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // fix constructor reference
Dog.prototype.bark = function () {
return "Woof!";
};
const rex = new Dog("Rex", "Lab");
rex.eat(); // "Rex is eating" — from Animal.prototype
rex.bark(); // "Woof!" — from Dog.prototypeProperty Shadowing
When an object has its own property that matches a prototype property:
const parent = { type: "parent", greet() { return "parent greet"; } };
const child = Object.create(parent);
child.type = "child"; // shadows parent.type
console.log(child.type); // "child" (own property)
console.log(child.greet()); // "parent greet" (from prototype)
delete child.type;
console.log(child.type); // "parent" (falls back to prototype)Method Lookup Performance
JavaScript searches the prototype chain every time you access a property. Own properties are fastest:
// Fast: own property
const obj = { x: 1 };
obj.x; // found immediately
// Slower: prototype property
const child = Object.create(obj);
child.x; // searches child first, then obj
// Use hasOwnProperty to check
obj.hasOwnProperty("x"); // true
child.hasOwnProperty("x"); // false
Object.hasOwn(child, "x"); // false (ES2022)for...in and Prototypes
for...in iterates over all enumerable properties, including inherited ones:
const parent = { a: 1 };
const child = Object.create(parent);
child.b = 2;
for (const key in child) {
console.log(key); // "b", "a" (includes inherited!)
}
// Filter to own properties only
for (const key in child) {
if (Object.hasOwn(child, key)) {
console.log(key); // "b" only
}
}
// Better: use Object.keys (only own enumerable)
Object.keys(child); // ["b"]Interview Questions
Q: What's the difference between __proto__ and prototype?
Answer: __proto__ is a property on every object that points to its parent in the prototype chain. prototype is a property on constructor functions that becomes the __proto__ of instances created with new.
Q: What's at the end of every prototype chain?
Answer: null. Object.prototype.__proto__ is null.
Q: How does method lookup work?
Answer: When you access a property, JavaScript first checks the object itself. If not found, it checks __proto__, then __proto__.__proto__, and so on until it reaches null. If still not found, it returns undefined.