cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

The prototype chain

Learn how JavaScript property lookups walk from an object to its prototype, how shadowing works, how to tell own from inherited properties, and why this still points at the receiver in inherited methods.

By the end, you can
  • 01
    Trace a lookupFollow rabbit → animal → Object.prototype → null and predict the result.
  • 02
    Tell own from inheritedChoose the right check: Object.hasOwn, in, hasOwnProperty, isPrototypeOf, or propertyIsEnumerable.
  • 03
    Use inherited methods safelyExplain why this in an inherited method is the object before the dot.

Prototype links

Every ordinary JavaScript object has an internal link called [[Prototype]]. When you read a property and the object does not own that property, JavaScript follows the link to another object and tries again. That repeated search is the prototype chain.

This builds on Object basics, where you met in, Object.hasOwn, and inherited toString; Constructors & new, where new links instances to Constructor.prototype; Methods & this and The this keyword, where the call-site chooses this; and Scope, where the scope chain finds variables. Scope is for names. Prototypes are for properties.

Real-life analogyThe shop, warehouse, and factory

Ask a shop for batteries. The clerk checks the shelf. If the shelf is empty, they call the warehouse. If the warehouse is empty, the warehouse calls the factory. Eventually someone has the item, or the answer is “sorry.” Property lookup feels the same.

In real life: The shop shelf
In JavaScript: The object you read from
In real life: The warehouse
In JavaScript: That object's prototype
In real life: The factory behind the warehouse
In JavaScript: The prototype's prototype
In real life: Sorry, we don't stock it
In JavaScript: Lookup reaches null, so the value is undefined

Where the analogy stops: A shop clerk might order new stock for you. JavaScript lookup never invents a property; it only checks each object in order.

About __proto__

The legacy __proto__ accessor usually lives on Object.prototype, so normal objects can use it to read or set their prototype link. Objects created with Object.create(null) do not inherit that accessor. Prefer Object.getPrototypeOf, Object.setPrototypeOf, and Object.create. The object literal form { __proto__: animal } is standardized and shown below.

Object literal __proto__ syntaxPop out in the code editor (opens in a new tab)JavaScript
const animal = { eats: true };const rabbit = { __proto__: animal, jumps: true };console.log(Object.getPrototypeOf(rabbit) === animal);console.log(rabbit.eats);

Lookup & shadowing

STEP THROUGH

Start with two objects. rabbit owns jumps. It does not own eats, but its prototype, animal, does. It also inherits familiar methods like toString from Object.prototype, which sits farther up the chain.

Trace a property lookup
Step 0 of 7Ready
Your turn: follow the blue line

Predict each lookup. Then step through the real path from rabbit to animal, to Object.prototype, and finally null.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const rabbit = Object.create(animal);rabbit.jumps = true; console.log(rabbit.jumps);console.log(rabbit.eats);console.log(typeof rabbit.toString);console.log(rabbit.fly);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 6: which property should rabbit read?

Changing the read starts a fresh replay. Predict whether lookup finds a value before you step.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Reading and writing are not mirror images. Reads climb the chain. Ordinary writes place a new property on the receiver, which can shadow an inherited property with the same name.

Reads climb, writes shadow
Step 0 of 7Ready
Your turn: follow the blue line

Watch the read/write difference: reads climb the chain, but ordinary writes create an own property on the receiver.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const rabbit = Object.create(animal); rabbit.eats = false;console.log(rabbit.eats);console.log(animal.eats); delete rabbit.eats;console.log(rabbit.eats);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Setters are the important write exception

If the prototype has an inherited setter for that name, assignment calls the setter instead of creating a plain data property. The setter still receives this as the object you assigned through.

Inherited setter exceptionPop out in the code editor (opens in a new tab)JavaScript
const animal = {  set mood(value) {    this.savedMood = value;  },};const rabbit = Object.create(animal);rabbit.mood = "curious";console.log(rabbit.savedMood);console.log(Object.hasOwn(rabbit, "mood"));

Own vs inherited properties

INTERACTIVE

An own property is stored directly on the object. An inherited property is found by following the prototype chain. Both are read with the same dot syntax, so you need deliberate checks when ownership matters.

Chain visualizer
Visualizer setupPop out in the code editor (opens in a new tab)JavaScript
const animal = { eats: true, walk() {} };const rabbit = Object.create(animal);rabbit.jumps = true; let current = rabbit;while (current !== null) {  // Check own properties, then climb.  current = Object.getPrototypeOf(current);}
Real lookup patheats
  1. rabbitno own eats
  2. animaleats: true

Lookup stops at the first owner.

Try it yourself
Try jumps, eats, toString, or fly.

Lookup found eats on animal with value true.

This is a conceptual visualizer, but it walks the real chain with Object.getPrototypeOf and checks ownership with Object.hasOwn.
Real-life analogyA family recipe card

You can cook from the family recipe without owning a copy. If you write your own version and put it on your fridge, you use that first. Remove your note, and the family binder is visible again.

In real life: A recipe in the family binder
In JavaScript: An inherited method or value
In real life: Your handwritten variation
In JavaScript: An own property that shadows it
In real life: Throwing away your variation
In JavaScript: delete revealing the inherited value again

Where the analogy stops: Family members might physically copy the recipe. JavaScript does not copy inherited properties during lookup.

Own or inherited?
  • rabbit.jumps after rabbit.jumps = true
  • rabbit.eats when only animal.eats exists
  • rabbit.toString from ordinary objects
  • rabbit.fly when no object in the chain has it
  • rabbit.eats after rabbit.eats = false
  • rabbit.secret inherited from animal
Try it yourself
0 of 6 correct

Sort each read by where JavaScript finds the property in the lesson's rabbit → animal chain.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

hasOwnProperty, isPrototypeOf & propertyIsEnumerable

Different tools answer different questions. Use the exact question you mean: “does this object own it?”, “can lookup find it?”, “is this object in the chain?”, or “will enumeration include it?”

Property checks compared
ToolAnswersUse it when
Object.hasOwn(obj, key)Own onlySafe even if obj has no prototype or shadows hasOwnProperty
obj.hasOwnProperty(key)Own onlyWorks on normal objects, but can be missing or shadowed
key in objOwn or inheritedGood for availability, not ownership
proto.isPrototypeOf(obj)Prototype relationshipAsks whether proto appears anywhere in obj's chain
obj.propertyIsEnumerable(key)Own and enumerableFalse for inherited properties and non-enumerable own properties
Object.keys(obj)Own enumerable stringsDoes not include inherited keys
for...inEnumerable strings, own and inheritedOften pair with Object.hasOwn inside the loop
Real checks on one chainPop out in the code editor (opens in a new tab)JavaScript
const animal = { eats: true };Object.defineProperty(animal, "secret", {  value: "warehouse",  enumerable: false,});const rabbit = Object.create(animal);rabbit.jumps = true; console.log(Object.hasOwn(rabbit, "jumps"));console.log(Object.hasOwn(rabbit, "eats"));console.log("eats" in rabbit);console.log(Object.keys(rabbit).join(","));console.log(animal.isPrototypeOf(rabbit));console.log(animal.propertyIsEnumerable("secret"));

Object.hasOwn is safer than obj.hasOwnProperty because it still works for null-prototype objects and objects that define their own property named hasOwnProperty. propertyIsEnumerable is stricter: the property must be own and enumerable.

this in inherited methods

STEP THROUGH

A method can be found on a prototype but still act on the object before the dot. In rabbit.walk(), lookup finds walk on animal, but the call-site sets this to rabbit. The method below is inline on purpose so production minifiers cannot detach it and change the this demo.

this follows the call-site
Step 0 of 6Ready
Your turn: follow the blue line

Step through an inherited method. The important question is not where the method was found, but which object was before the dot when it was called.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
  walk() {    this.isWalking = true;  },};const rabbit = Object.create(animal); rabbit.walk();console.log(rabbit.isWalking);console.log(animal.isWalking);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

This is why shared prototype methods are useful: one function can serve many objects, while state such as isWalking lands on the receiver.

Where you’ll use this

Prototype lookup explains why arrays all have map, why dates all have toISOString, why constructor instances share methods, and why classes can store methods once instead of copying them to every object. The next lesson, F.prototype & constructors, connects new to this link.

It also prevents bugs. A mutable object stored on a prototype is shared by every inheriting object. Mutating it through one child mutates the shared value for all children.

Bug: mutating a shared prototype arrayPop out in the code editor (opens in a new tab)JavaScript
const animal = { skills: [] };const rabbit = Object.create(animal);const fox = Object.create(animal); rabbit.skills.push("jump");fox.skills.push("sneak");console.log(rabbit.skills.join(","));
Fix: create own state before mutatingPop out in the code editor (opens in a new tab)JavaScript
const animal = { skills: [] };const rabbit = Object.create(animal);const fox = Object.create(animal); rabbit.skills = [];fox.skills = [];rabbit.skills.push("jump");fox.skills.push("sneak");console.log(rabbit.skills.join(","));

Common misconceptions

“Inherited properties are copied onto the object.”

No copy happens. The object keeps a link, and lookup follows it when needed.

“in means own.”

in means lookup can find the property, including inherited ones. Use Object.hasOwn for ownership.

“Changing a child changes the prototype.”

Ordinary assignment creates or updates the child’s own property. Setters are the key exception.

“The scope chain and prototype chain are the same.”

Scope resolves variable names. Prototypes resolve object properties.

“__proto__ is modern API style.”

The literal form is standard, but the accessor is legacy. Prefer the Object methods.

“Putting arrays on prototypes is harmless.”

Methods are great to share. Mutable data like arrays is usually per-object state, not prototype state.

Practice: trace the chain

5 EXERCISES
Exercise 1 · Warm-upPredict the revealed value

Predict what the program prints.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const animal = { eats: true };
const rabbit = Object.create(animal);
rabbit.eats = false;
delete rabbit.eats;
console.log(rabbit.eats);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeCount own vs inherited

    Type both outputs, separated by a comma.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const animal = { eats: true, sleeps: true };
    const rabbit = Object.create(animal);
    rabbit.jumps = true;
    rabbit.eats = false;
    console.log(Object.keys(rabbit).length);
    console.log("sleeps" in rabbit);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · ChallengeFix shared mutable prototype state

      The starter prints jump,sneak. Change it so rabbit.skills prints only jump.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const animal = { skills: [] };
      const rabbit = Object.create(animal);
      const fox = Object.create(animal);
      
      rabbit.skills.push("jump");
      fox.skills.push("sneak");
      console.log(rabbit.skills.join(","));
        Exercise 4 · PracticeChoose the relationship check

        Which method tells you whether animal is in rabbit’s prototype chain?

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeExplain this in an inherited method

          After rabbit.walk() in the lesson’s method example, where is isWalking created?

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS

            Read each code sample as a chain trace: where is the property stored, and does this operation read, write, delete, or call?

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What is an object's [[Prototype]]?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this shadowing example print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const animal = { eats: true };
              const rabbit = Object.create(animal);
              rabbit.eats = false;
              console.log(animal.eats);

              Choose an answer to see the explanation.

            3. Question 3 of 7Which check includes inherited properties?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does this inherited method example print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const animal = { walk() { this.isWalking = true; } };
              const rabbit = Object.create(animal);
              rabbit.walk();
              console.log(Object.hasOwn(rabbit, "isWalking"));

              Choose an answer to see the explanation.

            5. Question 5 of 7Which statement about __proto__ is accurate?

              Choose an answer to see the explanation.

            6. Question 6 of 7What does this shared array example print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const animal = { skills: [] };
              const rabbit = Object.create(animal);
              const fox = Object.create(animal);
              rabbit.skills.push("jump");
              fox.skills.push("sneak");
              console.log(rabbit.skills.join(","));

              Choose an answer to see the explanation.

            7. Question 7 of 7What does Object.keys(rabbit) include?

              Choose an answer to see the explanation.

            Key takeaways

            • [[Prototype]] is an internal object link used for property lookup.
            • Lookup checks own properties first, then prototypes, and returns undefined after null.
            • Shadowing happens when an own property hides an inherited one.
            • Object.hasOwn checks ownership; in checks availability through the chain.
            • Inherited methods get this from the call-site, so rabbit.walk() writes to rabbit.

            One-liner.
            The prototype chain is JavaScript’s property fallback path: object first, prototypes next, null last.

            Up next: F.prototype & constructors.

            CompleteFrontend Clear concepts. Working examples.