Skip to main content

Додавання методів після створення об'єкта

Так, можна. Об'єкти в JavaScript динамічні: достатньо присвоїти об'єкту нову властивість, значенням якої є функція, і вона одразу стає повноцінним методом.

Теорія

TL;DR

  • Метод, це звичайна властивість, значення якої, функція; тому її можна додати будь-коли.
  • Найкоротший спосіб: obj.method = function () { ... }.
  • Кілька методів зручно додати одним викликом Object.assign(obj, { ... }).
  • Щоб метод отримали всі екземпляри, додайте його в прототип: User.prototype.method = ....
  • Для методів беріть звичайні функції: стрілкові не мають власного this.

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

javascript
const user = { name: 'Maria' }; // додаємо метод після створення user.sayHi = function () { console.log(`Hello, ${this.name}!`); }; user.sayHi(); // "Hello, Maria!"

Метод sayHi з'явився вже після оголошення об'єкта, і тепер він є повноцінним методом цього об'єкта.

Просте присвоєння функції

Найпоширеніший спосіб, пряме присвоєння. Методів можна додавати скільки завгодно і коли завгодно:

javascript
const calculator = {}; calculator.add = function (a, b) { return a + b; }; calculator.multiply = function (a, b) { return a * b; }; console.log(calculator.add(2, 3)); // 5 console.log(calculator.multiply(2, 3)); // 6

Працює і запис через квадратні дужки, коли ім'я методу обчислюється: obj['say' + 'Hi'] = function () {}.

Стрілкові функції: можна, але обережно

javascript
user.sayBye = () => { console.log(`Bye, ${user.name}!`); }; user.sayBye(); // "Bye, Maria!"

Різниця:

  • function () має власний this, який під час виклику user.sayHi() вказує на сам об'єкт;
  • стрілкова функція => не має власного this, тому всередині неї this не посилається на об'єкт, а береться з зовнішньої області видимості.

Саме тому в прикладі вище довелося звертатися до user.name через зовнішню змінну, а не через this.name. Зазвичай для методів використовують звичайні функції, а не стрілкові.

Кілька методів одразу через Object.assign()

javascript
const user = { name: 'Maria' }; Object.assign(user, { sayHi() { console.log(`Hello, ${this.name}`); }, sayBye() { console.log(`Bye, ${this.name}`); } }); user.sayHi(); // "Hello, Maria" user.sayBye(); // "Bye, Maria"

Зручно, коли треба додати відразу кілька методів або «підмішати» в об'єкт готовий набір поведінки (mixin).

Метод у прототипі, тобто для всіх екземплярів

javascript
function User(name) { this.name = name; } User.prototype.sayHi = function () { console.log(`Hello, ${this.name}`); }; const maria = new User('Maria'); const oleh = new User('Oleh'); maria.sayHi(); // "Hello, Maria" oleh.sayHi(); // "Hello, Oleh"

Цей спосіб додає метод усім екземплярам, створеним через new User(), зокрема й тим, які вже існували на момент додавання: пошук іде ланцюжком прототипів під час виклику. Функція при цьому зберігається в пам'яті в одному примірнику, а не копіюється в кожен об'єкт.

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

СпосібКоли використовуватиПриклад
obj.method = function () {}додати один методuser.sayHi = ...
Object.assign(obj, { ... })додати кілька методівObject.assign(user, { sayHi, sayBye })
prototype.method = ...додати метод усім екземплярамUser.prototype.sayHi = ...

Одним реченням: у JavaScript методи можна додавати в об'єкт у будь-який момент, просто присвойте йому функцію, і вона стане методом:

javascript
obj.newMethod = function () { ... };

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

  • Використовувати стрілкову функцію як метод. У неї немає власного this, тому this.name дасть undefined або звернеться до зовнішнього контексту.
  • Втрачати this під час передавання методу. setTimeout(user.sayHi, 100) викличе функцію без об'єкта. Потрібно user.sayHi.bind(user) або обгортка () => user.sayHi().
  • Дописувати методи до вбудованих прототипів. Розширення Array.prototype чи Object.prototype ламає чужий код і псує цикли for...in.
  • Додавати метод до замороженого об'єкта. Після Object.freeze(obj) присвоєння мовчки нічого не зробить, а в 'use strict' кине TypeError.
  • Перезаписувати наявну властивість. Присвоєння з тим самим іменем тихо замінює те, що там було, тому перевіряйте ключ через Object.hasOwn().
  • Вважати, що пізно доданий метод відрізняється від оголошеного в літералі. Різниці немає: це та сама звичайна властивість зі значенням-функцією.

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

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

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