Property lookup in the prototype chain
Short answer
When you access an object's property, for example:
obj.propJavaScript searches for this property in the following order:
- First in the object itself (
obj); - If not found - in its prototype (
obj.__proto__orObject.getPrototypeOf(obj)); - Then - in the prototype's prototype, and so on;
- Until it reaches
null(the top of the chain).
If the property is not found anywhere - the result is undefined.
This sequence is called the prototype chain.
Example: step-by-step search
const animal = { eats: true };
const dog = Object.create(animal);
dog.barks = true;
console.log(dog.barks); // found in dog → true
console.log(dog.eats); // not in dog → look in animal → true
console.log(dog.toString); // not in animal → look in Object.prototype → [Function]
console.log(dog.fly); // not found anywhere → undefinedChain:
dog → animal → Object.prototype → nullVisually
dog {
barks: true
}
↑
|
animal {
eats: true
}
↑
|
Object.prototype {
toString(), hasOwnProperty(), ...
}
↑
|
nullAlgorithm under the hood (step by step)
When obj.prop is executed:
- JS checks:
does the property
propexist on the object itself (own property)? → if yes - return its value. → if no - move on. - JS gets the object's prototype:
const parent = Object.getPrototypeOf(obj);- Checks whether
propexists onparent. - Repeats the steps until:
- the property is found
- or the prototype equals
null
All of this happens dynamically, without copying properties.
When writing a property (obj.prop = value)
Here the mechanism is a bit different:
- If the property exists on the object itself, → it is simply overwritten.
- If not - a new property is created on
obj(not on the prototype). - The prototype is not touched at all.
const animal = { eats: true };
const dog = Object.create(animal);
dog.eats = false; // creates a new property on dog
console.log(dog.eats); // false (own)
console.log(animal.eats); // true (on the prototype, unchanged)Reading and writing use different chains
| Operation | Where it looks | What it does |
|---|---|---|
obj.prop (read) | Looks in obj, then up the chain | Returns the first one found |
obj.prop = value (write) | Always writes to obj, if writable: true | Does not change the prototype |
delete obj.prop | Deletes only on obj | Does not affect the prototype |
If the chain has a getter or setter
If a getter (get prop()) is found at any level, it executes.
If a setter is found, it executes on write.
const animal = {
get info() {
return 'Animal info';
}
};
const dog = Object.create(animal);
console.log(dog.info); // "Animal info" - the prototype's getter was calledThat is, prototypes can contain "reactive" properties, not just data.
Example with a "deep" chain
const a = { level: 'A' };
const b = Object.create(a);
const c = Object.create(b);
const d = Object.create(c);
console.log(d.level); // "A"The search goes through 4 objects before finding level on a.
Engine optimization
JS engines (V8, SpiderMonkey, etc.) optimize the prototype chain:
- they create internal "shape" maps (object structures);
- they cache found properties;
- the cache is invalidated when the prototype or properties change.
That's why changing the prototype at runtime (Object.setPrototypeOf) is
a slow operation, and it is best avoided.
Example: what happens if the prototype is null
const pure = Object.create(null);
pure.key = 'value';
console.log(pure.toString); // undefined (no Object.prototype)Here the chain breaks immediately:
pure → nullThe search stops instantly if the prototype equals null.
SUMMARY
| Stage | What happens |
|---|---|
| 1 | JS looks for the property on the object itself |
| 2 | If not found - it goes to [[Prototype]] |
| 3 | It continues up the chain |
| 4 | If it reaches null - it returns undefined |
| Note | On write, a new property is created on the object, not on the prototype |
| Note | Getters/setters in the chain are also taken into account |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.