All topics
Objectsintermediate

Prototype Chain Explained

How objects inherit properties and methods from other objects through an internal link called the prototype, forming a chain up to Object.prototype.

JavaScript is a prototype-based language, meaning inheritance works through objects linking directly to other objects, rather than through classes copying behavior at compile time the way class-based languages traditionally do. Understanding the prototype chain is essential because it's the actual mechanism underneath both old-style constructor functions and modern ES6 classes, and interviewers use it to distinguish candidates who understand JS deeply from those who've only used the class syntax on the surface.

The prototype chain is like an org chart for answering questions: you ask your direct teammate (own properties) first; if they don't know, you escalate up to their manager (prototype), then their manager's manager, until someone up the chain has the answer or you reach the CEO (Object.prototype) with nowhere further to go.

Key Concepts

1
Every object has an internal [[Prototype]] link (exposed via Object.getPrototypeOf() or the legacy __proto__ accessor) pointing to another object, or to null if it's at the top of the chain. When you access a property on an object, the engine first checks the object's own properties; if not found, it follows the [[Prototype]] link and checks that object's own properties, continuing up the chain until it finds the property or reaches an object whose prototype is null (typically Object.prototype, whose own prototype is null).
[[Prototype]]Object.getPrototypeOf()__proto__nullObject.prototype
2
Constructor functions create this link automatically: calling new Foo() creates a new object whose [[Prototype]] is set to Foo.prototype, so any methods defined on Foo.prototype become accessible on every instance without being copied onto each one individually — they're looked up dynamically via the chain instead. class syntax in ES6 works identically under the hood; class Foo {} still creates a Foo.prototype object, and methods defined in the class body land there, not on individual instances.
new Foo()[[Prototype]]Foo.prototypeclassclass Foo {}
3
This lookup-by-chain design has real consequences: modifying a method on a shared prototype instantly affects every existing instance (since they all look it up dynamically at access time, not at creation time), and setting a property directly on an instance 'shadows' the same-named property further up the chain without deleting or modifying it — reading it afterward returns the instance's own value, but deleting the instance's own property reveals the prototype's original value again.