█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/JavaScript (Standalone Deep Dive)/Prototypes and the Prototype Chain
45 minIntermediate

Prototypes and the Prototype Chain

After this lesson, you will be able to: Understand the prototype chain, how inheritance works without classes, and what ES6 classes actually compile to.

ES6 classes are syntactic sugar over prototypes. Understanding the underlying model is what makes 'this' debuggable.

Prerequisites:Closures and Scope

Every object has a __proto__

Property lookup walks the prototype chain.

tsx
const animal = { speak() { return "..."; } };
const dog = Object.create(animal); // dog's __proto__ = animal
dog.bark = function () { return "Woof"; };
dog.bark(); // "Woof", found on dog
dog.speak(); // "...", found via dog.__proto__
dog.unknown; // undefined, chain ends at Object.prototype
// Modern: Object.getPrototypeOf(dog) === animal

ES6 classes — sugar over prototypes

Same chain, friendlier syntax.

tsx
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks`; }
}
const d = new Dog("Rex");
d.speak(); // "Rex barks"
// Under the hood:
// d.__proto__ === Dog.prototype
// Dog.prototype.__proto__ === Animal.prototype
// Animal.prototype.__proto__ === Object.prototype

Why this matters: `this` binding

In methods, `this` is whatever called the method (the object before the dot). Detached: `const fn = obj.method; fn();` → `this` is undefined (strict) or global. Arrow functions DON'T have their own `this`; they inherit from enclosing scope. Use arrow functions for callbacks; regular methods for class methods.

this gotcha

The most-asked JS this question.

tsx
class Counter {
constructor() { this.count = 0; }
increment() { this.count++; }
}
const c = new Counter();
setTimeout(c.increment, 1000); // TypeError: Cannot set property 'count' of undefined
// `c.increment` is a bare function reference; `this` is lost.
// Fix 1: bind
setTimeout(c.increment.bind(c), 1000);
// Fix 2: arrow wrapper
setTimeout(() => c.increment(), 1000);
// Fix 3: class field arrow (auto-bound)
class Counter {
count = 0;
increment = () => { this.count++; };
}

Common mistakes only experienced JS devs avoid

Modifying built-in prototypes (Array.prototype.x = ...). Breaks everyone else's code. Confusing `instanceof` with prototype-chain inheritance. Detached methods losing `this`. Using arrow functions for class methods that should be on the prototype (memory hit: one copy per instance).

Quick Check

Why does `class Foo { bar() {} }` add `bar` to `Foo.prototype` instead of each instance?

Pick the cleanest answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Closures and Scope
Back to JavaScript (Standalone Deep Dive)
Functional Programming in JS→