You type class Dog extends Animal in your React class components. TypeScript infers both layers, your editor jumps to the definitions, and the keyword does its job without ever asking you to explain it. Over the next seven screens you're going to lose the class keyword. You'll rebuild extends from functions and prototype — one wall at a time — until you can write by hand what every line of class X extends Y compiles to, and read a transpiled bundle line by line.
Start with the first line every candidate writes when the interviewer takes the keyword away: Dog.prototype = new Animal(). A Dog IS-A Animal, right? Tests pass. rex.walk() returns "Rex walks". rex instanceof Animal is true. Ship it. A week later, a bug report says Rex's bone is in Bo's pocket. Nothing in the code looks like it could do that. Below is the workbench that reproduces it.
// Phase 1 — the naive wire.function Animal() { this.inventory = []; // installed on the ONE Animal built below.}function Dog(name) { this.name = name; }Dog.prototype = new Animal(); // 👈 one Animal — every Dog's __proto__.const rex = new Dog('Rex');const bo = new Dog('Bo');const max = new Dog('Max');// rex.__proto__ === bo.__proto__ === max.__proto__ → true// rex.inventory → chain walks to sharedAnimal.inventory → []// (press Rex: add bone to see what happens)Look at the diagram. Three Dogs on the left — Rex, Bo, Max — each roped to ONE object in the middle: a single Animal, built once when the module loaded. That is what Dog.prototype = new Animal() actually did. new Animal() ran ONE time, at class-definition, and pinned the resulting instance as every Dog's __proto__. The inventory: [] field lives on that one Animal, not on each Dog. When the runtime looks up rex.inventory, it walks the rope to that shared object and reads the same array Bo and Max will read too.
Before you tap Rex: add bone — predict what happens to Bo and Max.