# How JavaScript's Prototype Chain Works for Inheritance: Delegation vs. Copying

> Understand JavaScript's prototype chain inheritance. Learn how delegation via [[Prototype]] enables property lookups across object chains, unlike simple copying. Unlock efficient JS inheritance.

- Repository: [Kyle Simpson/You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS)
- Tags: deep-dive
- Published: 2026-02-24

---

**JavaScript implements inheritance through an internal hidden linkage called `[[Prototype]]` that delegates property lookups up a chain of objects until finding the property or reaching `null`.**

Unlike class-based languages that copy inheritance down to instances, JavaScript's model links objects to other objects through a live delegation mechanism. As detailed in the [You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS) repository, specifically in [`objects-classes/ch2.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/objects-classes/ch2.md), this prototype chain enables objects to share behavior without duplicating data across memory.

## What Is the `[[Prototype]]` Linkage?

Every JavaScript object has an internal, hidden property called **`[[Prototype]]`** (also referred to as the *prototype chain*). When you create an object literal like `const myObj = {}`, the engine automatically sets its `[[Prototype]]` to reference **`Object.prototype`**.

According to the source code analysis in [`objects-classes/ch2.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/objects-classes/ch2.md) (lines 67-73), this linkage is established at instantiation and serves as the fallback mechanism for property resolution. If a requested property does not exist as an **own property** on the object, the engine delegates the lookup to the object referenced by `[[Prototype]]`, continuing upward until the property is found or the chain terminates.

## How Prototype Delegation Works

The lookup process follows a strict delegation pattern. When you access `myObj.toString()`, the engine first checks if `myObj` has an own property `toString`. If not, it walks up to `Object.prototype` where `toString` is defined, as implemented in the specification covered in [`objects-classes/ch2.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/objects-classes/ch2.md) (lines 91-99).

The chain terminates at **`Object.prototype`**, whose own `[[Prototype]]` is `null`. This prevents infinite lookup loops and defines the top of the inheritance hierarchy.

```javascript
const person = {
  name: 'Alice',
  greet() {
    return `Hi, I'm ${this.name}`;
  }
};

person.greet();               // "Hi, I'm Alice" (own property)
person.toString();            // "[object Object]" (inherited from Object.prototype)

```

## Creating Custom Prototype Links

You can establish custom prototype relationships using **`Object.create(proto)`** or the **`__proto__`** literal property introduced in ES6.

### Using `Object.create()`

The `Object.create()` method creates a new object with its `[[Prototype]]` explicitly set to the provided object, as documented in [`objects-classes/ch2.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/objects-classes/ch2.md) (lines 44-52):

```javascript
const animal = {
  eats: true,
  speak() { return '...'; }
};

const rabbit = Object.create(animal);
rabbit.name = 'Bunny';
rabbit.speak = () => '...hop...';

console.log(rabbit.eats);    // true (delegated from animal)
console.log(rabbit.speak()); // "...hop..." (own property shadows prototype)

```

### Using `__proto__` Literal Syntax

For object literals, you can specify the prototype directly:

```javascript
const vehicle = { wheels: 4 };
const car = {
  __proto__: vehicle,
  brand: 'Toyota'
};

console.log(car.wheels);   // 4 (inherited via prototype chain)

```

### Null-Prototype Objects

To create "dictionary" objects that inherit nothing—not even `Object.prototype` methods—use `Object.create(null)`:

```javascript
const dict = Object.create(null);
dict.foo = 'bar';
console.log('toString' in dict); // false (no prototype pollution)

```

This pattern prevents accidental name collisions with inherited properties like `constructor` or `toString`.

## Constructor Functions and the `prototype` Property

A critical distinction exists between **`[[Prototype]]`** (the internal linkage on instances) and **`prototype`** (the public property on constructor functions). As explained in [`objects-classes/ch2.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/objects-classes/ch2.md) (lines 94-102), when you invoke a function with `new`, the engine sets the new instance's `[[Prototype]]` to reference the constructor's `prototype` object.

```javascript
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function () {
  return `Hello, ${this.name}`;
};

const bob = new Person('Bob');
console.log(bob.greet());   // "Hello, Bob"
console.log(Object.getPrototypeOf(bob) === Person.prototype); // true

```

Functions themselves also inherit from **`Function.prototype`**, which provides methods like `call`, `apply`, and `bind`. This is detailed in [`objects-classes/ch2.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/objects-classes/ch2.md) (lines 16-20).

## Live Linkage and Shadowing

The prototype chain maintains a **live link** to the delegated object. Changes to a prototype immediately affect all objects that delegate to it, unless those objects define their own property that **shadows** the inherited one:

```javascript
const base = { kind: 'base' };
const obj = Object.create(base);

console.log(obj.kind); // "base"

base.kind = 'updated';
console.log(obj.kind); // "updated" (live delegation)

obj.kind = 'shadowed';
console.log(obj.kind);       // "shadowed" (own property)
console.log(base.kind);      // "updated" (unchanged)

```

## Summary

- **`[[Prototype]]`** is an internal reference that creates the inheritance chain, automatically set to `Object.prototype` for object literals.
- **Delegation** allows property lookups to fall back to the prototype chain rather than copying properties during instantiation.
- **`Object.create(proto)`** and **`__proto__`** literals allow explicit configuration of an object's prototype.
- **`Object.create(null)`** generates dictionary objects with zero inheritance, preventing prototype pollution.
- **`prototype`** (on functions) differs from **`[[Prototype]]`** (on instances); the former becomes the latter when using the `new` keyword.
- The chain terminates at `Object.prototype`, whose `[[Prototype]]` is `null`.

## Frequently Asked Questions

### What is the difference between `__proto__` and `prototype`?

`__proto__` (or `Object.getPrototypeOf()`) exposes the internal **`[[Prototype]]`** linkage on any object instance, indicating which object it delegates to. In contrast, **`prototype`** is a property that exists only on constructor functions (like `Person` or `Array`), serving as the template object that becomes the `[[Prototype]]` of instances created with `new`.

### How do I check if a property is inherited or an own property?

Use the **`hasOwnProperty`** method to distinguish own properties from inherited ones. For example, `obj.hasOwnProperty('toString')` returns `false` for most objects because `toString` is inherited from `Object.prototype`, while `obj.hasOwnProperty('customProp')` returns `true` for properties defined directly on the object.

### Is JavaScript's prototype chain inheritance slower than class-based inheritance?

Property lookup performance depends on chain depth. Accessing properties on objects with long prototype chains requires walking multiple links, which is marginally slower than direct property access. However, modern JavaScript engines optimize prototype chains heavily, and the memory efficiency of shared methods via delegation often outweighs negligible lookup costs.

### Can I change an object's prototype after it is created?

Yes, using **`Object.setPrototypeOf()`** or the non-standard `__proto__` setter, but this is discouraged for performance reasons. Changing an object's prototype invalidates engine optimizations that assume stable prototype structures. It is better to create a new object with the desired prototype using `Object.create()` rather than mutating existing prototype links.