Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 11

The Prototype Chain

Prerequisites: this chapter assumes you already know objects, property access, functions, and `this` binding, and are comfortable reading ordinary JavaScript. You do not need prior knowledge of `class` syntax; we build up to it.
Level: AdvancedLength: In depth3 min read

Read at another depth

The Prototype Chain

Prerequisites: this chapter assumes you already know objects, property access, functions, and this binding, and are comfortable reading ordinary JavaScript. You do not need prior knowledge of class syntax; we build up to it.

The core mechanism

Every object in JavaScript has an internal link to another object, its prototype. When you read obj.prop, the engine first checks obj's own properties. If the property is absent, it follows that internal link and checks the prototype object, then its prototype, and so on, until it either finds the property or reaches the end of the chain (null). This is the prototype chain.

The internal link is not a normal property. It is exposed through Object.getPrototypeOf(obj) (read) and Object.setPrototypeOf(obj, proto) (write, slow and best avoided). Objects created with literal syntax have Object.prototype as their prototype.

Code example in javascript
const obj = { a: 1 };
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype)); // null — end of chain
console.log(obj.toString); // function — found on Object.prototype, not on obj
console.log('a' in obj);        // true (own or inherited)
console.log(Object.hasOwn(obj, 'a')); // true (own only)

Property writes behave differently: assignment to obj.prop = x always creates or updates an own property on obj (subject to setters on the prototype, discussed below). Reads walk the chain; writes do not.

Constructor functions and `.prototype`

Functions get a second role. Any regular function has a .prototype property — an object that becomes the prototype of objects created by calling the function with new.

Code example in javascript
function Point(x, y) {
  this.x = x;       // own property, per instance
  this.y = y;
}
Point.prototype.dist = function () {   // shared by all instances
  return Math.hypot(this.x, this.y);
};

const p = new Point(3, 4);
console.log(Object.hasOwn(p, 'x'));    // true
console.log(Object.hasOwn(p, 'dist')); // false — inherited
console.log(Object.getPrototypeOf(p) === Point.prototype); // true

The design consequence: state that varies per instance goes on the instance in the constructor; behavior shared by all instances goes on the constructor's .prototype. Methods stored per-instance cost memory and defeat identity comparison, a common mistake.

Two more pieces:

  • Every function object inherits from Function.prototype (which gives you call, apply, bind), and Function.prototype inherits from Object.prototype. So methods exist two chains deep on functions.
  • The .constructor property you often see on instances is not special. It is just an inherited, writable data property of Function.prototype's default .prototype object. Overwrite .prototype with a fresh object and you lose it unless you restore it.
Code example in javascript
Point.prototype = { dist() { return 0; } };
console.log(new Point(1, 2).constructor === Point); // false
Point.prototype.constructor = Point; // conventional repair

`class` is syntax over the same chain

A class declaration creates a function whose .prototype holds its methods. extends sets up a chain between the two prototype objects and between the two constructors themselves (so static methods inherit too), and wires up super.

Code example in javascript
class Shape {
  area() { return 0; }
}
class Circle extends Shape {
  constructor(r) { super(); this.r = r; }
  area() { return Math.PI * this.r ** 2; }
}
const c = new Circle(1);
console.log(Object.getPrototypeOf(c) === Circle.prototype);          // true
console.log(Object.getPrototypeOf(Circle.prototype) === Shape.prototype); // true
console.log(Object.getPrototypeOf(Circle) === Shape); // statics chain too

class is not a new object model; it is enforced discipline over the one above: methods are non-enumerable, classes must be called with new (no implicit this), and the chain is immutable.

Gotchas and failure modes

  • Mutating shared prototypes. Adding to Object.prototype or Array.prototype pollutes every object in the program, including library code. Avoid it; if you must (polyfills), use Object.defineProperty with enumerable: false.
  • for...in walks inherited enumerable properties. Prefer Object.keys/Object.entries (own keys only), or guard with Object.hasOwn.
  • Shadowing. Assigning c.area = ... creates an own property that hides the inherited one. The inherited method still exists on the prototype; other instances are unaffected. This is per-instance override, not mutation of the prototype.
  • Setters intercept writes. If a prototype has a setter for prop, then obj.prop = v invokes that setter instead of creating an own property — even though reads fall through to the prototype. Use Object.defineProperty(obj, ...) to force an own data property.
  • Performance. Very long chains and setPrototypeOf defeat the engine's inline caches. Shapes that access the same properties through stable chains are fast; polymorphic, reshaped chains are not.
  • __proto__ vs prototype. obj.__proto__ (legacy, deprecated but widely supported) is the instance's prototype link. Func.prototype is the template for instances of Func. They are different things and confusion between them is the classic beginner error; at this level, always reach for Object.getPrototypeOf.

Decision criteria

Use plain objects with the literal prototype when you have data with a handful of shared methods. Use class when you have a real type hierarchy with instanceof and super needs. Use closure-based factories (no prototype at all) when you want true privacy or per-instance method identity — accepting the memory cost. Avoid Object.setPrototypeOf in hot code, and avoid deep chains beyond two or three levels: they are hard to debug and slow to optimize.

Exercise

Given const a = { greet() {} }; const b = Object.create(a); b.greet = function () {}; — does assigning b.greet change which function a.greet is, or what other objects see?

Show answer

No. The assignment creates an own greet property on b that shadows the inherited one. a.greet is untouched, and any other object with a in its chain still resolves to a's original method.

Exercise

Why does typeof Circle === 'function' and Object.getPrototypeOf(Circle) === Shape hold for classes, and what does the second fact give you?

Show answer

A class declaration compiles to a constructor function, so it is a function object. extends sets the class's own prototype (the static chain) to the superclass, so static members and Circle.__proto__-level lookups inherit from Shape — this is how static inheritance works.

Spotted a mistake, or code that does not work?

Report an issue

Chapter: The Prototype Chain

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that