Prototype chain
Trace property lookup, inheritance, classes, own properties, and shared behavior through JavaScript's prototype chain.

WHAT YOU WILL BE ABLE TO DO
Learning outcomes
- Explain prototype chain in plain language.
- Connect the behavior to the underlying browser or framework model.
- Implement the core pattern and reason through edge cases.
- Answer common follow-ups without relying on memorized phrases.
01Overview
Every object has an internal [[Prototype]] link (accessible via Object.getPrototypeOf or the non-standard __proto__). Property lookups that miss on the object itself walk up this chain until they hit Object.prototype or null.
02Mental model
This is delegation, not copying — instances share behavior through the chain instead of duplicating methods. class/extends syntax builds and wires this same prototype chain automatically; it doesn't introduce a separate inheritance model.
03Examples
const animal = { speak() { return 'generic sound'; } };const dog = Object.create(animal);dog.speak(); // 'generic sound' — found via the prototype chaindog.hasOwnProperty('speak'); // false — it's inherited, not own04Check understanding
What does hasOwnProperty tell you that a plain property check doesn't?
obj.prop can return an inherited value; hasOwnProperty confirms the property exists directly on the object, not somewhere up the prototype chain.
DDConcept deep dives
Deep dive 1
Property lookup follows internal prototype links
Reading a property first checks the receiver's own property descriptor. If absent, lookup follows [[Prototype]] repeatedly until it finds a descriptor or reaches null. If the descriptor is a getter, the getter executes with the original receiver as this, which lets inherited accessors operate on instance data.
- Object.hasOwn distinguishes direct data from inherited data.
- The in operator reports both own and inherited properties.
- Shadowing creates an own property with the same name; it does not alter the prototype property.
Deep dive 2
new connects instances to constructor prototypes
A new call creates an object whose prototype normally points at Constructor.prototype, binds this to it, executes the constructor, and returns the created object unless the constructor explicitly returns another object. Methods placed on the prototype are shared; methods created inside the constructor are allocated per instance.
- Constructor.prototype is a property on the function, not the function's own [[Prototype]].
- class syntax defines prototype methods and clearer inheritance rules over the same object model.
- Object.create lets code choose a prototype without running a constructor.
Deep dive 3
Prototype mutation crosses trust boundaries
Changing a widely shared prototype affects every object that inherits from it. Unsafe recursive merges can allow keys such as __proto__ or constructor.prototype to write attacker-controlled values into a shared prototype. Code that trusts inherited configuration or authorization flags can then behave incorrectly.
- Validate structured input and allowlist expected keys at the boundary.
- Use Object.hasOwn for security-sensitive records.
- Null-prototype objects can be useful dictionaries but still require schema validation.
QAInterview questions and model answers
Attempt each answer aloud before opening it. The model answer shows the depth and precision expected in an interview; it is not a script to memorize.
Intermediate · Coding · 1 min · Question 1How does property lookup use the prototype chain?Open model answer
Model answer
The engine first checks the object's own properties. If absent, it follows the object's internal [[Prototype]] link and repeats until it finds a property or reaches null. Accessor properties may execute a getter with the original receiver as this.
const animal = { speak() { return 'generic'; } };const dog = Object.create(animal);dog.bark = () => 'woof';
dog.bark(); // 'woof' — own propertydog.speak(); // 'generic' — found one level up on `animal`dog.fly; // undefined — chain ends at Object.prototype -> nullIntermediate · Coding · 1 min · Question 2How are constructor.prototype and an instance's prototype related?Open model answer
Model answer
When a constructable function is called with new, the new object's [[Prototype]] is normally set to the constructor's prototype property. The prototype property itself is just an ordinary property on the constructor function; it is not the constructor's own prototype.
function Point(x) { this.x = x; }Point.prototype.describe = function () { return `x=${this.x}`; };
const p = new Point(3);Object.getPrototypeOf(p) === Point.prototype; // truep.describe(); // "x=3" (via the chain)Intermediate · Conceptual · 1 min · Question 3What does the class syntax change?Open model answer
Model answer
Classes provide clearer syntax and semantics over prototype-based behavior: methods live on the prototype, constructors initialize instances, and extends links both constructor and prototype chains. Classes are strict, cannot be called without new, and support private fields.
Open question page →Intermediate · Coding · 1 min · Question 4What is the difference between own and inherited properties?Open model answer
Model answer
Own properties are directly stored on the object and can be checked with Object.hasOwn. The in operator also considers the prototype chain. Object.keys enumerates own enumerable string-keyed properties only.
const base = { inherited: 1 };const obj = Object.create(base);obj.own = 2;
'inherited' in obj; // true — walks the chainObject.hasOwn(obj, 'inherited'); // false — only this objectObject.keys(obj); // ['own']Intermediate · Conceptual · 1 min · Question 5Why is mutating built-in prototypes risky?Open model answer
Model answer
It changes behavior globally, can collide with future platform additions, affects unrelated code, and complicates enumeration and security assumptions. Use standalone utilities, composition, or carefully scoped polyfills that follow standards.
Open question page →Advanced · Coding · 1 min · Question 6What is prototype pollution?Open model answer
Model answer
It is modification of a shared prototype through unsafe handling of keys such as __proto__, constructor, or prototype. Inherited attacker-controlled values can alter authorization or configuration logic. Validate keys, use safe merge utilities, and prefer null-prototype dictionaries where appropriate.
// Unsafe deep-merge lets a payload reach Object.prototype:merge({}, JSON.parse('{"__proto__": {"isAdmin": true}}'));({}).isAdmin; // true — every plain object is now affected
// Safer: reject dangerous keys, or use Object.create(null) dictionaries.Intermediate · Conceptual · 1 min · Question 7How does instanceof work?Open model answer
Model answer
It generally checks whether the constructor's prototype object appears in the candidate object's prototype chain, with Symbol.hasInstance allowing customized behavior.
Open question page →Advanced · Conceptual · 1 min · Question 8What does Object.setPrototypeOf cost?Open model answer
Model answer
Changing an existing object's prototype can invalidate engine optimizations and affect later property lookup. Create objects with the desired prototype instead of mutating hot objects.
Open question page →Intermediate · Conceptual · 1 min · Question 9What is a property descriptor?Open model answer
Model answer
It defines a property's value and writability or getter and setter, plus enumerability and configurability. Assignment behavior depends on descriptors found across the chain.
Open question page →Beginner · Conceptual · 1 min · Question 10Why can for...in be dangerous for record iteration?Open model answer
Model answer
It enumerates enumerable string properties from both the object and its prototypes. Object.keys or Object.entries better expresses own-property record iteration.
Open question page →SCScenario questions
Scenario 1
A configuration merge accepts JSON input and unrelated objects later gain an isAdmin property. What happened?
- Inspect recursive merge handling of special property names.
- Check both own properties and inherited values.
- Reproduce with a minimal payload.
- Block dangerous paths and replace the unsafe merge implementation.
Reveal worked answer
This suggests prototype pollution. A recursive merge likely traversed __proto__ or constructor.prototype and wrote to Object.prototype. I would patch the merge boundary, allowlist expected schema keys, use Object.hasOwn when consuming security-sensitive data, upgrade the affected dependency, and assess whether polluted state crossed a trust boundary.