Skip to main content

Ключове слово super

super дає доступ до батьківського класу зсередини нащадка. Як виклик, super(...), він запускає конструктор батька і створює this; як об'єкт, super.x, він читає члени батьківського прототипу або самої батьківської функції.

Теорія

TL;DR

  • super(name) у конструкторі викликає конструктор батька і ініціалізує this.
  • До виклику super() звертання до this кидає ReferenceError.
  • У звичайних методах super вказує на Parent.prototype, тому super.method() дорівнює Parent.prototype.method.call(this).
  • У статичних методах super вказує на сам Parent, тобто на його статику.
  • super() дозволений тільки всередині класу з extends, інакше це SyntaxError.
  • Стрілкові функції не мають власного super і беруть його із зовнішнього контексту класу.

Швидкий приклад

javascript
class Animal { constructor(name) { this.name = name; } } class Dog extends Animal { constructor(name, breed) { super(name); // calls Animal.constructor(name) this.breed = breed; } } const dog = new Dog("Rex", "shepherd"); console.log(dog.name); // "Rex" console.log(dog.breed); // "shepherd"

super() у конструкторі: виклик батька

Що відбувається під капотом, коли один клас успадковує інший:

  1. До виклику super() об'єкт this ще не існує.
  2. Виклик super(name) виконує конструктор батька (Animal) і створює this, який уже можна використовувати.
  3. Лише після цього можна присвоювати поля в this.

Якщо спробувати використати this до super(), рушій кине помилку:

javascript
class Dog extends Animal { constructor(name) { this.name = name; // ReferenceError super(name); } }

ReferenceError: Must call super constructor before accessing 'this'

Причина проста: саме super() ініціалізує контекст екземпляра. Без нього this ще не створено.

super поза конструктором: методи батька

super працює не лише в конструкторі, а і в будь-якому методі класу, щоб викликати батьківську реалізацію.

javascript
class Animal { speak() { console.log("The animal makes a sound"); } } class Dog extends Animal { speak() { super.speak(); // calls the parent method console.log("The dog barks"); } } new Dog().speak(); // "The animal makes a sound" // "The dog barks"

Так само зручно нарощувати результат батьківського методу замість того, щоб дублювати його код:

javascript
class Animal { constructor(name) { this.name = name; } info() { return `Name: ${this.name}`; } } class Dog extends Animal { constructor(name, breed) { super(name); // calls Animal.constructor() this.breed = breed; } info() { return `${super.info()}, breed: ${this.breed}`; } } const dog = new Dog("Rex", "Beagle"); console.log(dog.info()); // Name: Rex, breed: Beagle

super у статичних методах

Якщо в класу є статичні методи, super усередині них звертається до статики батька:

javascript
class Parent { static sayHi() { console.log("Hello from the parent"); } } class Child extends Parent { static sayHi() { super.sayHi(); // calls Parent.sayHi() console.log("Hello from the child"); } } Child.sayHi(); // Hello from the parent // Hello from the child

На що насправді вказує super

Під капотом super це посилання на батьківський об'єкт, і цей об'єкт різний залежно від того, де ви пишете super:

  • у звичайних методах super вказує на Parent.prototype;
  • у статичних методах super вказує на сам Parent.

Тому виклик:

javascript
super.method()

еквівалентний:

javascript
Parent.prototype.method.call(this)

Важлива деталь: this залишається поточним екземпляром, тобто батьківський метод бачить дані нащадка.

super і стрілкові функції

Стрілкові функції не мають власного super і беруть його із зовнішнього контексту, тому в полі-стрілці класу super працює:

javascript
class A { hello() { console.log("Hello from A"); } } class B extends A { hello = () => { super.hello(); // works: super is taken from the class body }; } new B().hello(); // "Hello from A"

Пам'ятайте лише, що методи-стрілки створюються на екземплярі, а не в прототипі, тож кожен об'єкт отримує власну копію функції.

Зведення:

Де використовуєтьсяЩо робить
У конструкторіВикликає конструктор батька і створює this
У методіВикликає батьківський метод (super.method())
У статичному методіЗвертається до статичних методів батька
Без extendsПомилка
До виклику super()this недоступний, буде помилка

Типові помилки

  • Виклик super() у класі без extends: це SyntaxError, бо батька просто немає.
javascript
class A { constructor() { super(); // SyntaxError } }
  • Присвоєння полів у this до super(). Порядок завжди такий: спершу super(...), потім this.x = ....
  • Пропущений super() у конструкторі нащадка: конструктор завершиться помилкою, щойно торкнеться this.
  • Очікування, що super.method() викличе метод з this.__proto__. Ні, super прив'язаний до класу, у якому написаний метод, а не до типу поточного об'єкта.
  • Спроба написати super.constructor() замість super(). Це різні речі: створює екземпляр саме super().

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.