Prototype Chain: __proto__ vs prototype Deep Dive
Property nahi mila? Dada se pucho! Yeh hai prototype chain — JS ka asli DNA.
Every object has an internal link to another object: its prototype. When you access a property that doesn't exist on the object itself, JavaScript follows this link and looks in the prototype. If it's not there either, it follows the next link. This continues until the property is found or the chain ends at null.
This is the delegation model — objects delegate property lookups to their prototypes. It's like asking your father, who asks his father, who asks his father... until someone has the answer or there's nobody left to ask.
const grandpa = { wisdom: 'Old school' };
const parent = Object.create(grandpa);
parent.money = 100;
const child = Object.create(parent);
child.name = 'Sai';
console.log(child.name); // 'Sai' (own property)
console.log(child.money); // 100 (found on parent)
console.log(child.wisdom); // 'Old school' (found on grandpa)
// The lookup chain:
// child -> parent -> grandpa -> Object.prototype -> null
Object.prototype.__proto__ === null. Object.prototype is the final link. Every ordinary object's chain eventually reaches Object.prototype and then null. This is why all objects have methods like toString() and hasOwnProperty() — they're defined on Object.prototype.These two are the most confused concepts in JavaScript. Let's clear it once and for all.
__proto__ is an accessor property on every object. It points to the object's prototype — the object it delegates to. It is the actual link in the prototype chain.
.prototype is a property on only function objects. It is the object that will become the __proto__ of objects created with new.
obj.__proto__ === Constructor.prototype (if obj was created via new Constructor). A function's .prototype is NOT its own __proto__. The function's __proto__ is Function.prototype.function User(name) {
this.name = name;
}
User.prototype.greet = function() {
return 'Hi, ' + this.name;
};
const sai = new User('Sai');
// __proto__ vs prototype
console.log(sai.__proto__ === User.prototype); // true!
// sai does NOT have a .prototype property (only functions do)
// User's own __proto__ points to Function.prototype
console.log(User.__proto__ === Function.prototype); // true
// User's .prototype is what instances will inherit
console.log(typeof User.prototype); // 'object'
// The instance chain:
// sai -> User.prototype -> Object.prototype -> null
If an object and its prototype both have the same property name, the object's own property "shadows" the prototype's.
Reading: Finds the own property first and stops looking up the chain.
Writing: Always affects the own property (creates it if it doesn't exist), never the prototype's.
The only exception: setters on the prototype can intercept writes.
const proto = {
greet() { return 'Hello from proto'; },
name: 'ProtoName'
};
const obj = Object.create(proto);
obj.name = 'ObjName'; // Creates OWN property, shadows proto.name
console.log(obj.name); // 'ObjName' (own property wins)
console.log(obj.greet()); // 'Hello from proto' (inherited)
// Deleting the own property reveals the prototype's
delete obj.name;
console.log(obj.name); // 'ProtoName' (proto's name is visible again!)
// Writing to an inherited property NEVER changes the prototype
obj.greet = function() { return 'Overridden!'; };
console.log(proto.greet()); // 'Hello from proto' (unchanged)Object.create(proto) creates a new object with the specified prototype. No constructor function needed — pure prototypal inheritance.
Object.create(null) creates an object with no prototype at all — a pure dictionary with no toString, no hasOwnProperty, nothing inherited.
Object.create(proto, propertyDescriptors) can also define properties on creation using the same descriptor format as Object.defineProperty.
// Prototypal inheritance without constructors
const animal = {
speak() { return this.sound; }
};
const dog = Object.create(animal);
dog.sound = 'Woof!';
console.log(dog.speak()); // 'Woof!'
// The "null prototype" object — no inherited methods
const dict = Object.create(null);
dict.key = 'value';
// dict.toString(); // TypeError! No prototype means no methods.
// dict.hasOwnProperty('key'); // TypeError!
console.log('key' in dict); // true (in operator works)
console.log(Object.hasOwn(dict, 'key')); // true (safe check)
// Why Object.create(null)? Perfect for dictionaries.
// No risk of colliding with Object.prototype properties like 'toString'.Object.setPrototypeOf(obj, newProto) changes an object's prototype after it has been created. NEVER DO THIS IN PRODUCTION.
Why? Because changing a prototype means V8 must throw away the old Hidden Class and create a new one. V8 then has to de-optimize all Inline Caches that cached the old prototype chain.
The only safe time to set a prototype is during object creation.
const fast = { a: 1 };
// fast's hidden class and ICs are optimized
// THE PERFORMANCE KILLER
const newProto = { b: 2 };
Object.setPrototypeOf(fast, newProto);
// V8: "The whole hidden class chain is invalid!"
// V8: "I must de-optimize every function that touched 'fast'."
// Safe way: Set prototype at creation
const safe = Object.create(newProto);
safe.a = 1; // Prototype is fixed, hidden class is stable.
Lo kar liya — Key Points:
- ✅ Prototype chain: Objects delegate property lookups to their prototype, which delegates to its prototype, until null.
- ✅
__proto__is the ACTUAL link on every object;.prototypeis a property on functions used bynew. - ✅ Property shadowing: An own property hides a prototype property of the same name. Writes never modify the prototype.
- ✅
Object.create(proto)creates a new object with the given prototype;Object.create(null)creates a pure dictionary. - ✅
Object.setPrototypeOfis extremely slow; it invalidates V8 hidden classes and inline caches. Avoid it. - ✅ Prototype chain lookups are O(chain length); deep chains are slower than shallow ones.
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login