Пошук уроків, статей та іншого контенту
Синтаксис class, конструктори, успадкування через extends/super, статичні методи та приватні поля.
Синтаксис class, доданий у ES2015, не запроваджує нову модель успадкування — це синтаксичний цукор (syntactic sugar) над тими самими функціями-конструкторами й прототипами з попереднього уроку. Методи класу автоматично потрапляють у прототип, так само, як у прикладі з Animal.prototype.speak, лише без ручного написання цього коду:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} видає звук`;
}
}
const dog = new Animal("Рекс");
dog.speak(); // "Рекс видає звук"Перевірка: typeof Animal === "function" — це підтверджує, що class справді компілюється у функцію-конструктор із методами в прототипі, а не в окремий вид сутності.
constructor викликається автоматично під час new ClassName(...) і призначений для встановлення початкового стану екземпляра. Клас без явного constructor отримує порожній за замовчуванням.
extends встановлює прототипний зв'язок між класами, а super викликає конструктор чи методи батьківського класу:
class Dog extends Animal {
constructor(name, breed) {
super(name); // обов'язково викликати перед використанням this у дочірньому класі
this.breed = breed;
}
speak() {
return `${super.speak()} (гав!)`; // виклик методу батьківського класу
}
}
const rex = new Dog("Рекс", "Лабрадор");
rex.speak(); // "Рекс видає звук (гав!)"У конструкторі дочірнього класу super(...) обов'язково має бути викликаний до першого звернення до this — інакше рушій кине ReferenceError. Це відображає реальний механізм: this ще не існує, поки батьківський конструктор не відпрацював.
Метод чи поле, позначені static, належать самому класу, а не окремим екземплярам — викликаються через ім'я класу, а не через new:
class MathHelper {
static square(x) {
return x * x;
}
}
MathHelper.square(4); // 16 — без створення екземпляра через newПоля з префіксом # (доданий у ES2022) недоступні ззовні класу — це справжня приватність на рівні мови, а не угода на кшталт підкреслення в імені, яку раніше доводилось використовувати:
class BankAccount {
#balance; // приватне поле — оголошується заздалегідь
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
this.#balance += amount;
return this.#balance;
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
account.getBalance(); // 150
account.#balance; // SyntaxError — приватне поле недоступне ззовніЦе той самий результат приватного стану, якого раніше досягали через замикання й фабричні функції (модуль «Функції», createBankAccount) — але тепер це вбудована мовна можливість класів, а не патерн, який доводилося будувати вручну.
const dog = new Dog(); // ReferenceError: Cannot access 'Dog' before initialization
class Dog {}Клас підпорядковується правилам тимчасової мертвої зони (TDZ), як let/const із попереднього уроку — на відміну від function declaration, оголосити клас і використати його раніше в коді не можна.
Забутий super(...) у конструкторі дочірнього класу перед зверненням до this.
Спроба викликати статичний метод через екземпляр (dog.square()) замість через клас (Dog.square()).
Очікування, що клас можна використати до його оголошення в коді, як function declaration.
class — це читабельніший синтаксис над прототипним успадкуванням із попереднього уроку: методи автоматично потрапляють у прототип, extends/super керують успадкуванням між класами, static оголошує члени самого класу, а приватні поля (#) дають справжню інкапсуляцію стану. Розуміння прототипів під капотом допомагає розібратися в помилках успадкування, які інакше здаються незрозумілою «магією».
Спробуйте самостійно
Створіть клас Shape з методом area(), що повертає 0, і дочірній клас Circle extends Shape з приватним полем #radius та власним area(), що перевизначає (overrides) метод батьківського класу.