Prototype Chain in JavaScript: Complete Guide

Every JavaScript object links to another object through its prototype. Learn how the prototype chain works, how property lookup walks it, and why it powers JavaScript inheritance.

7 min read

The prototype chain is the mechanism JavaScript uses to share properties and methods between objects. Every object has an internal link that points to another object. When you read a property, JavaScript checks the object itself first, then follows that link to the next object if needed, and keeps going until it finds the property or the chain reaches null.

javascriptjavascript
const parent = { shared: "I am inherited" };
const child = Object.create(parent);
child.own = "I belong to child";
 
console.log(child.own);     // "I belong to child", found on child
console.log(child.shared);  // "I am inherited", found on parent
console.log(child.missing); // undefined, not found anywhere

Child only has one own property: own. The shared property lives on parent, but child can still reach it through the prototype chain. When a property is nowhere in the chain, JavaScript returns undefined rather than throwing.

The Chain in Diagrams

A three-level prototype chain

Every plain object created with curly braces has Object.prototype as its prototype. That object provides methods like toString and hasOwnProperty that every plain object inherits, and the chain stops at null because Object.prototype itself has no prototype.

How Property Lookup Works

When you write obj.someProperty, the engine looks for it on obj first. If it is missing there, it follows the internal link to the next object and repeats the search, all the way until it finds the property or reaches null.

javascriptjavascript
const grandparent = { a: 1 };
const parent = Object.create(grandparent);
parent.b = 2;
const child = Object.create(parent);
child.c = 3;
 
console.log(child.c); // 3, found on child itself
console.log(child.b); // 2, found on parent
console.log(child.a); // 1, found on grandparent
console.log(child.z); // undefined, reached null

This is a linked-list walk, not a copy. A child cannot delete or modify a property that lives higher up the chain, though it can shadow that property by creating its own with the same name.

Property Shadowing

If an object has a property with the same name as one on its prototype, the own property wins. This is called shadowing.

javascriptjavascript
const proto = { value: "from prototype" };
const obj = Object.create(proto);
obj.value = "from object";
 
console.log(obj.value); // "from object", own property wins

Setting obj.value creates a new own property; it never modifies the prototype's version, which is still there just hidden behind the closer match. Shadowing is how method overriding works: a child object can define its own version of a method that takes precedence over the parent's.

javascriptjavascript
const animal = {
  speak() { return "Some generic sound"; }
};
 
const dog = Object.create(animal);
dog.speak = function () { return "Woof!"; };
 
console.log(dog.speak()); // "Woof!"

Built-in Prototype Chains

Every built-in type has its own prototype chain. Arrays, functions, and dates all get their methods this way rather than storing a copy on each value.

javascriptjavascript
const arr = [1, 2, 3];
console.log(Object.getPrototypeOf(arr) === Array.prototype); // true
 
function fn() {}
console.log(Object.getPrototypeOf(fn) === Function.prototype); // true
 
const d = new Date();
console.log(Object.getPrototypeOf(d) === Date.prototype); // true

Array.prototype contains methods like map, filter, and push. Function.prototype contains call, bind, and apply. Every one of these chains eventually leads to Object.prototype and then null.

Changing the Prototype

The clean way to set an object's prototype is Object.create(), since it wires up the link at the moment the object is made.

javascriptjavascript
const parent = { color: "blue" };
const child = Object.create(parent);
child.size = "large";
 
console.log(Object.getPrototypeOf(child) === parent); // true

You can also use the proto key inside an object literal, which is standardized for exactly this purpose and reads a bit more naturally in some code.

javascriptjavascript
const child2 = { __proto__: { color: "blue" }, size: "large" };
console.log(child2.color); // "blue"

Object.setPrototypeOf() can change an existing object's prototype, but avoid it when possible. Changing the prototype after creation disrupts engine optimizations and can make property access noticeably slower. Set the prototype at creation time with Object.create() or the proto literal key instead.

Checking Own vs Inherited Properties

Since the prototype chain makes inherited properties look like own properties at first glance, you sometimes need to check where a property actually lives.

javascriptjavascript
const parent = { inherited: true };
const child = Object.create(parent);
child.own = true;
 
console.log(child.hasOwnProperty("own"));       // true
console.log(child.hasOwnProperty("inherited")); // false
console.log("inherited" in child);              // true
CheckLooks at own properties only?Looks at the whole chain?
hasOwnProperty()YesNo
in operatorNoYes

Use hasOwnProperty(), or the newer Object.hasOwn(), whenever you need to distinguish an object's own properties from properties it only inherits.

Object.create(null): No Prototype

You can create an object with no prototype at all, which is useful for a pure dictionary that should never collide with inherited keys.

javascriptjavascript
const dict = Object.create(null);
dict.hello = "world";
 
console.log(dict.hello);      // "world"
console.log(dict.toString);   // undefined, no Object.prototype at all

Objects like this lack every Object.prototype method, so use Object.hasOwn(dict, "hello") instead of dict.hasOwnProperty("hello"), since the latter does not exist on a null-prototype object.

The Prototype Chain in Practice

Here is a concrete example showing how the chain lets you build a simple inheritance model out of plain objects, without any class syntax at all.

javascriptjavascript
const vehicle = {
  type: "vehicle",
  describe() { return `This is a ${this.type}`; }
};
 
const car = Object.create(vehicle);
car.type = "car";
car.drive = function () { return `${this.describe()} that drives.`; };
 
console.log(car.drive()); // "This is a car that drives."

Car inherits describe from vehicle and overrides type with its own value. When car.drive() calls this.describe(), JavaScript walks the chain, finds describe on vehicle, and runs it with this still pointing at car. That is prototype-based inheritance: objects link to other objects, and behavior is shared through the chain rather than copied.

For how constructors and classes use this mechanism to build reusable object factories, see constructor functions and class inheritance.

Rune AI

Rune AI

Key Insights

  • Every object has an internal [[Prototype]] link to another object or null.
  • Property lookup walks the chain from the object upward until the property is found or null is reached.
  • Own properties shadow inherited properties with the same name.
  • Object.prototype sits at the top of most chains; its prototype is null.
  • Use Object.getPrototypeOf() and Object.create() for standard prototype operations.
RunePowered by Rune AI

Frequently Asked Questions

Can an object have no prototype?

Yes. You can create an object with null prototype using Object.create(null). Such an object does not inherit any methods from Object.prototype, so it has no toString(), hasOwnProperty(), etc. This is useful for dictionary-like objects where you want only own properties.

What happens at the end of the prototype chain?

Every prototype chain ends at null. Object.prototype is the default top of the chain for most objects, and Object.prototype's [[Prototype]] is null. When a property search reaches null without finding the property, the lookup stops and undefined is returned.

Is the prototype chain the same as the scope chain?

No. The scope chain determines where variables are looked up (based on where functions are nested in code). The prototype chain determines where object properties are looked up (based on the object's [[Prototype]] links). They are two separate mechanisms.

Conclusion

The prototype chain is the linked list of objects that JavaScript walks to find properties. Every object points to another object through its [[Prototype]] until the chain reaches null. When you access obj.something, JavaScript first checks obj itself, then walks the chain until it finds the property or reaches null. This is how inheritance works in JavaScript: not by copying, but by linking objects together through prototypes.