Як додати метод у класі
Метод у класі додають, просто записавши його в тілі класу: greet() { ... }, після чого він потрапляє у прототип і стає доступним усім екземплярам. Крім звичайного методу JavaScript дає статичні методи, геттери та сеттери, приватні методи з # і поля-методи зі стрілковою функцією, і кожен варіант вирішує свою задачу.
Теорія
TL;DR
- Звичайний метод
m() {}у тілі класу потрапляє уClass.prototypeі спільний для всіх екземплярів. - Метод можна дописати й після оголошення класу:
Class.prototype.m = function () {}. static m() {}належить самому класу, екземпляри його не бачать.getіsetдають доступ під виглядом звичайної властивості.#m() {}це справді приватний метод, доступний лише зсередини класу.- Поле-стрілка
m = () => {}не втрачаєthis, тому зручне для колбеків.
Швидкий приклад
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hi, ${this.name}!`);
}
}
const u = new User("Alice");
u.greet(); // Hi, Alice!Звичайний метод і додавання методу пізніше
Звичайний (публічний) метод доступний у всіх екземплярів класу:
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hi, ${this.name}!`);
}
}
const u = new User("Alice");
u.greet(); // Hi, Alice!Такі методи автоматично додаються в User.prototype, тобто розділяються всіма екземплярами, а не створюються заново для кожного об'єкта.
Метод можна додати у прототип класу і вже після оголошення, вручну:
class User {
constructor(name) {
this.name = name;
}
}
// Додаємо метод пізніше
User.prototype.sayBye = function () {
console.log(`${this.name} says: bye!`);
};
const u = new User("Alice");
u.sayBye(); // Alice says: bye!Це працює тому, що під капотом class це просто функція з prototype. Різниця в деталі: доданий вручну метод буде перелічуваним, тоді як методи з тіла класу, ні.
Статичний метод
Такий метод викликається безпосередньо на класі, а не на екземплярі:
class MathUtils {
static square(n) {
return n * n;
}
}
console.log(MathUtils.square(5)); // 25Екземпляри (
new MathUtils()) не мають доступу доstatic-методів.
Геттер і сеттер
Використовуються, щоб «замаскувати» властивості під методи і контролювати доступ до них:
class Product {
constructor(price) {
this._price = price;
}
get price() {
return this._price + " USD";
}
set price(value) {
if (value < 0) throw new Error("Price cannot be negative");
this._price = value;
}
}
const p = new Product(1000);
console.log(p.price); // "1000 USD"
p.price = 1500;
console.log(p.price); // "1500 USD"Під час читання
p.priceфактично викликаєтьсяget price(), а під час присвоєнняp.price = ...викликаєтьсяset price().
Приватні методи і поля-методи зі стрілкою
Приватні методи з решіткою недоступні ззовні, тільки всередині класу:
class Account {
#logBalance() {
console.log(`Current balance: ${this.balance}`);
}
constructor(balance) {
this.balance = balance;
this.#logBalance(); // викликати можна лише звідси
}
}
const acc = new Account(500);
// acc.#logBalance(); -> помилка, це приватний методЯкщо ж треба, щоб метод зберігав контекст this, його оголошують як поле зі стрілковою функцією:
class Button {
label = "Click me";
handleClick = () => {
console.log(`Clicked: ${this.label}`);
};
}
const b = new Button();
b.handleClick(); // Clicked: Click meТакі методи не втрачають this, навіть якщо передати їх як колбек:
setTimeout(b.handleClick, 1000); // усе працює коректноПлата за це: поле-стрілка створюється окремо для кожного екземпляра і не лежить у прототипі.
Підсумкова таблиця
| Тип методу | Синтаксис | Доступність | Особливості |
|---|---|---|---|
| Звичайний | method() {} | Через екземпляр | Спільний для всіх екземплярів |
| Статичний | static method() {} | Через сам клас | Не видно на екземплярах |
| Геттер / сеттер | get name() {}, set name(v) {} | Як властивість | Дозволяє контролювати доступ |
| Приватний | #method() {} | Лише всередині класу | Повна інкапсуляція |
| Поле-метод (стрілка) | method = () => {} | Через екземпляр | Не втрачає this |
Типові помилки
- Ставити кому або крапку з комою між методами в тілі класу: це не об'єктний літерал, роздільники там не потрібні.
- Робити всі методи полями-стрілками «щоб не думати про
this»: так кожен екземпляр отримує власні копії функцій і виграш прототипу зникає. - Викликати
static-метод на екземплярі та отримуватиTypeError. - Називати геттер так само, як поле (
get price()іthis.price = ...у конструкторі): вийде нескінченна рекурсія, тому у прикладі поле і назване_price. - Забувати, що
#-методи не видно навіть у нащадках: приватність у класах працює по класу, а не по ланцюжку прототипів.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.