Skip to main content

Як додати метод у класі

Метод у класі додають, просто записавши його в тілі класу: greet() { ... }, після чого він потрапляє у прототип і стає доступним усім екземплярам. Крім звичайного методу JavaScript дає статичні методи, геттери та сеттери, приватні методи з # і поля-методи зі стрілковою функцією, і кожен варіант вирішує свою задачу.

Теорія

TL;DR

  • Звичайний метод m() {} у тілі класу потрапляє у Class.prototype і спільний для всіх екземплярів.
  • Метод можна дописати й після оголошення класу: Class.prototype.m = function () {}.
  • static m() {} належить самому класу, екземпляри його не бачать.
  • get і set дають доступ під виглядом звичайної властивості.
  • #m() {} це справді приватний метод, доступний лише зсередини класу.
  • Поле-стрілка m = () => {} не втрачає this, тому зручне для колбеків.

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

javascript
class User { constructor(name) { this.name = name; } greet() { console.log(`Hi, ${this.name}!`); } } const u = new User("Alice"); u.greet(); // Hi, Alice!

Звичайний метод і додавання методу пізніше

Звичайний (публічний) метод доступний у всіх екземплярів класу:

javascript
class User { constructor(name) { this.name = name; } greet() { console.log(`Hi, ${this.name}!`); } } const u = new User("Alice"); u.greet(); // Hi, Alice!

Такі методи автоматично додаються в User.prototype, тобто розділяються всіма екземплярами, а не створюються заново для кожного об'єкта.

Метод можна додати у прототип класу і вже після оголошення, вручну:

javascript
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. Різниця в деталі: доданий вручну метод буде перелічуваним, тоді як методи з тіла класу, ні.

Статичний метод

Такий метод викликається безпосередньо на класі, а не на екземплярі:

javascript
class MathUtils { static square(n) { return n * n; } } console.log(MathUtils.square(5)); // 25

Екземпляри (new MathUtils()) не мають доступу до static-методів.

Геттер і сеттер

Використовуються, щоб «замаскувати» властивості під методи і контролювати доступ до них:

javascript
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().

Приватні методи і поля-методи зі стрілкою

Приватні методи з решіткою недоступні ззовні, тільки всередині класу:

javascript
class Account { #logBalance() { console.log(`Current balance: ${this.balance}`); } constructor(balance) { this.balance = balance; this.#logBalance(); // викликати можна лише звідси } } const acc = new Account(500); // acc.#logBalance(); -> помилка, це приватний метод

Якщо ж треба, щоб метод зберігав контекст this, його оголошують як поле зі стрілковою функцією:

javascript
class Button { label = "Click me"; handleClick = () => { console.log(`Clicked: ${this.label}`); }; } const b = new Button(); b.handleClick(); // Clicked: Click me

Такі методи не втрачають this, навіть якщо передати їх як колбек:

javascript
setTimeout(b.handleClick, 1000); // усе працює коректно

Плата за це: поле-стрілка створюється окремо для кожного екземпляра і не лежить у прототипі.

Підсумкова таблиця

Тип методуСинтаксисДоступністьОсобливості
Звичайнийmethod() {}Через екземплярСпільний для всіх екземплярів
Статичнийstatic method() {}Через сам класНе видно на екземплярах
Геттер / сеттерget name() {}, set name(v) {}Як властивістьДозволяє контролювати доступ
Приватний#method() {}Лише всередині класуПовна інкапсуляція
Поле-метод (стрілка)method = () => {}Через екземплярНе втрачає this

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

  • Ставити кому або крапку з комою між методами в тілі класу: це не об'єктний літерал, роздільники там не потрібні.
  • Робити всі методи полями-стрілками «щоб не думати про this»: так кожен екземпляр отримує власні копії функцій і виграш прототипу зникає.
  • Викликати static-метод на екземплярі та отримувати TypeError.
  • Називати геттер так само, як поле (get price() і this.price = ... у конструкторі): вийде нескінченна рекурсія, тому у прикладі поле і назване _price.
  • Забувати, що #-методи не видно навіть у нащадках: приватність у класах працює по класу, а не по ланцюжку прототипів.

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

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

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