Inheritance — extends & super
В одной фразе: extends устанавливает двойную прототипную цепочку — для экземпляров и для самих классов (static наследование); super() в дочернем конструкторе обязателен до первого обращения к this. На собесе проверяют что именно создаёт extends под капотом.
class Shape { constructor(color) { this.color = color; } area() { return 0; } toString() { return `${this.constructor.name}(${this.color})`; }}
class Circle extends Shape { #radius;
constructor(color, radius) { super(color); // ❗ обязателен до this — иначе ReferenceError this.#radius = radius; // только после super() }
area() { // override родительского метода return Math.PI * this.#radius ** 2; }
describe() { return `${super.toString()} r=${this.#radius}`; // super.method() }}// Что создаёт extends под капотом (концептуально):// 1. Circle.prototype = Object.create(Shape.prototype)// → экземпляры Circle находят методы Shape через цепочку// 2. Object.setPrototypeOf(Circle, Shape)// → статические методы Shape доступны как Circle.staticMethod()// 3. Circle.prototype.constructor = Circle
const c = new Circle('red', 5);c instanceof Circle; // truec instanceof Shape; // truec instanceof Object; // true
Object.getPrototypeOf(Circle.prototype) === Shape.prototype; // trueObject.getPrototypeOf(Circle) === Shape; // true (static!)// super.method() работает через [[HomeObject]] — не через thisclass Animal { speak() { return 'animal sound'; }}class Dog extends Animal { speak() { const parentSound = super.speak(); // [[HomeObject]] = Dog.prototype return `${parentSound} + bark`; }}new Dog().speak(); // 'animal sound + bark'
// Если дочерний класс не определяет constructor —// super() вызывается автоматически с forwarding всех аргументовclass Bulldog extends Dog {} // нет constructor — работает корректноnew Bulldog().speak(); // 'animal sound + bark'Итог: extends создаёт две прототипные цепочки: для экземпляров и для классов. super() создаёт this в дочернем конструкторе — без него this недоступен.