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.

Every object has a hidden link to another object. Looking up a property follows that chain until it is found or the chain ends.

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
    const animal = { speak() { return 'noise'; } };
    const dog = Object.create(animal);
    dog.name = 'Rex';
2
    dog.name      // own property
    dog.speak()   // not own -- found on animal
    dog.toString  // found on Object.prototype
3
    dog -> animal -> Object.prototype -> null
4
That is inheritance in JavaScript. There are no classes underneath — class is syntax over this.
class
5
Where the chain comes from.
    function Dog(name) { this.name = name; }
    Dog.prototype.speak = function () { return 'woof'; };
6
    const d = new Dog('Rex');
    Object.getPrototypeOf(d) === Dog.prototype   // true
7
new creates an object whose prototype is the constructor's .prototype property. The two are different things with confusingly similar names:
new.prototype
8
    Dog.prototype        the object instances will inherit from
    d.__proto__          the link on the instance itself
9
Methods live on the prototype for a reason. One copy, shared by every instance:
10
    // one function, ten thousand dogs
    Dog.prototype.speak = function () {};
11
    // ten thousand functions
    function Dog() { this.speak = function () {}; }
12
Own against inherited.
    d.hasOwnProperty('name')      // true
    d.hasOwnProperty('speak')     // false -- inherited
    'speak' in d                  // true  -- in checks the chain
13
    Object.keys(d)                // own enumerable only
    for (const k in d)            // includes inherited enumerable
14
That difference is why for...in over an object can surprise you, and why Object.keys is usually what was meant.
for...inObject.keys
15
Shadowing. Assigning a property that exists on the prototype creates an own property; it does not modify the prototype:
16
    d.speak = () => 'custom';     // only this instance changes
17
The practical points. Object.create(null) makes an object with no prototype at all — no toString, no hasOwnProperty — which is the right base for a dictionary of arbitrary keys.
Object.create(null)toStringhasOwnProperty
18
And modifying built-in prototypes (Array.prototype.myHelper = ...) affects every array in the program, including other libraries'. It is the reason that practice is universally discouraged.
Array.prototype.myHelper = ...
19
What the interviewer is probing.1. "What happens when you read a missing property?" Probing: lookup. Stalls: "It returns undefined." Moves up: the engine walks the prototype chain and only returns undefined once it reaches null at the end.
20
2. "What is the difference between prototype and __proto__?" Probing: the two names. Stalls: "They are the same." Moves up: prototype is a property on constructor functions used for new instances; __proto__ is the instance link to its prototype.
21
3. "Why is modifying Object.prototype dangerous?" Probing: global effect. Stalls: "It is handy." Moves up: every object inherits it, so it can break for-in loops and third-party code across the whole application.
22
4. "How do classes relate to prototypes?" Probing: the sugar. Stalls: "They are different systems." Moves up: class syntax creates the same prototype links — methods live on the prototype and extends sets the chain.