Prototype Chain

The chain of linked objects that powers JavaScript inheritance.

Chain Visualization

Objects linked in a chain, each inheriting from the next.

function Animal(name) { this.name = name; }
Animal.prototype.eat = function() { return "eating"; };

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() { return "Woof!"; };

const rex = new Dog("Rex", "Lab");

rex → Dog.prototype → Animal.prototype → Object.prototype → null

rexname: "Rex", breed: "Lab"
Dog.prototypebark(), constructor
Animal.prototypeeat(), constructor
Object.prototypetoString(), hasOwnProperty(), ...
nullend of chain

Built-in Chains

Every value in JavaScript has a prototype chain.

// Arrays:
[1,2,3].__proto__ === Array.prototype     // true
Array.prototype.__proto__ === Object.prototype // true
// Chain: [1,2,3] → Array.prototype → Object.prototype → null

// Strings:
"hello".__proto__ === String.prototype    // true
// Chain: "hello" → String.prototype → Object.prototype → null

// Functions:
function foo() {}
foo.__proto__ === Function.prototype      // true
// Chain: foo → Function.prototype → Object.prototype → null

// That's why arrays have .map(), strings have .slice(),
// and everything has .toString() — it's inherited!
ValueChain
[1, 2]→ Array.prototype → Object.prototype → null
"hello"→ String.prototype → Object.prototype → null
42→ Number.prototype → Object.prototype → null
function(){}→ Function.prototype → Object.prototype → null
{}→ Object.prototype → null

instanceof

Checks if an object's prototype chain contains a constructor's prototype.

function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);

const rex = new Dog();

rex instanceof Dog;    // true
rex instanceof Animal; // true
rex instanceof Object; // true

// instanceof walks up the chain:
// rex.__proto__ === Dog.prototype? ✓ → true
// rex.__proto__.__proto__ === Animal.prototype? ✓ → true

// Arrays:
[] instanceof Array;  // true
[] instanceof Object; // true (Array inherits from Object)

💡 instanceof checks the entire chain, not just the direct prototype. For exact type checking, use Object.getPrototypeOf(obj) === X.prototype.

Property Shadowing

Own properties override inherited ones with the same name.

const parent = { color: "blue", size: 10 };
const child = Object.create(parent);

child.color; // "blue" (inherited)
child.color = "red"; // creates OWN property
child.color; // "red" (own — shadows parent)
parent.color; // "blue" (unchanged!)

Setting a property on the child creates an own property that 'shadows' the inherited one. The parent is never modified.

💡 Writing always goes on the object itself, never up the chain
1 / 2

Extending Prototypes

Adding methods to built-in prototypes (and why you usually shouldn't).

// You CAN add to built-in prototypes:
Array.prototype.last = function() {
  return this[this.length - 1];
};
[1, 2, 3].last(); // 3

// But you SHOULDN'T because:
// 1. Future JS versions might add a different .last()
// 2. Libraries might conflict
// 3. for...in loops will iterate over added properties

// ✗ Don't modify: Object.prototype, Array.prototype, etc.
// ✓ Instead, use utility functions or extend with classes

⚠️ Modifying built-in prototypes is called "monkey-patching". It causes maintenance nightmares. Only polyfills (adding missing standard features to old browsers) justify it.

FAQ

Common questions about the prototype chain.