Способи створення об'єкта
У JavaScript об'єкт можна створити щонайменше десятьма способами, від літерала {} до Object.fromEntries(). Вибір залежить від того, чи потрібен шаблон із методами, чи явний прототип, чи просто копія наявних даних.
Теорія
TL;DR
- Об'єктний літерал
{}це найчитабельніший і найчастіший спосіб. new Object()робить те саме, але виглядає застаріло і майже не використовується.- Функція-конструктор із
newіclassстворюють об'єкти «за шаблоном»,classце синтаксичний цукор над функцією. - Фабрична функція просто повертає об'єкт, без
newі без прототипного спадкування. Object.create(proto)задає прототип явно.JSON.parse(),Object.assign(), spread{ ...obj }іObject.fromEntries()створюють об'єкт із готових даних.
Швидкий приклад
const user = { name: 'Oleh', age: 25, isAdmin: false };
// властивості можна додавати і видаляти динамічно
user.city = 'Kyiv';
delete user.isAdmin;
console.log(user); // { name: 'Oleh', age: 25, city: 'Kyiv' }Літерал і new Object()
Об'єктний літерал це найпростіший і найпоширеніший спосіб:
const user = {
name: 'Oleh',
age: 25,
isAdmin: false
};Той самий результат через конструктор:
const user = new Object();
user.name = 'Oleh';
user.age = 25;new Object() робить рівно те саме, що {}, але довше і виглядає «по-старому», тому зараз майже не використовується.
Шаблони: функція-конструктор і class
До появи class об'єкти «за шаблоном» створювали саме функцією-конструктором:
function User(name, age) {
this.name = name;
this.age = age;
}
const oleh = new User('Oleh', 25);
const alice = new User('Alice', 30);
console.log(oleh.name); // "Oleh"Коли функцію викликають із new, рушій під капотом:
- створює порожній об'єкт
{}; - присвоює його
this; - повертає цей об'єкт (якщо функція явно не повернула інший).
class з ES6 це той самий механізм, але зручніший синтаксис:
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHi() {
console.log(`Привіт, я ${this.name}`);
}
}
const oleh = new User('Oleh', 25);
oleh.sayHi(); // "Привіт, я Oleh"Методи класу живуть у User.prototype, тобто одна копія методу на всі екземпляри.
Фабрична функція і Object.create()
Замість class чи new можна просто повернути об'єкт:
function createUser(name, age) {
return {
name,
age,
sayHi() {
console.log(`Привіт, ${this.name}`);
}
};
}
const oleh = createUser('Oleh', 25);
oleh.sayHi(); // "Привіт, Oleh"Дуже зручний спосіб, особливо коли не потрібні prototype і спадкування. Мінус у тому, що кожен екземпляр отримує власну копію методу.
Object.create() створює новий об'єкт із вказаним прототипом:
const person = {
greet() {
console.log(`Привіт, я ${this.name}`);
}
};
const user = Object.create(person);
user.name = 'Oleh';
user.greet(); // "Привіт, я Oleh"Використовується, коли треба явно задати ланцюжок прототипів (prototype chain). Окремий випадок, Object.create(null), дає «чистий» об'єкт без жодних успадкованих методів, зручний як словник.
Створення з готових даних
З рядка JSON, типовий випадок для відповіді сервера:
const json = '{"name": "Oleh", "age": 25}';
const user = JSON.parse(json);
console.log(user.name); // "Oleh"Працює тільки з простими типами даних, методи через JSON не передаються.
Object.assign() створює об'єкт на основі інших, копіюючи властивості:
const base = { a: 1 };
const extra = { b: 2 };
const result = Object.assign({}, base, extra);
console.log(result); // { a: 1, b: 2 }Spread-синтаксис робить те саме коротше і є сучасним стандартом копіювання та об'єднання:
const user = { name: 'Oleh', age: 25 };
const copy = { ...user, city: 'Kyiv' };
console.log(copy); // { name: 'Oleh', age: 25, city: 'Kyiv' }Object.fromEntries() збирає об'єкт із масиву пар [ключ, значення]:
const entries = [['name', 'Oleh'], ['age', 25]];
const user = Object.fromEntries(entries);
console.log(user); // { name: 'Oleh', age: 25 }Що обирати
| Спосіб | Приклад | Особливості |
|---|---|---|
| Об'єктний літерал | { name: 'Oleh' } | найчастіший спосіб |
new Object() | new Object() | рідко використовується |
| Функція-конструктор | function User() { this.name = ... } | стара альтернатива class |
class | class User { ... } | сучасний ООП-підхід |
| Фабрична функція | function createUser() { return {...} } | без this, просто повертає об'єкт |
Object.create(proto) | Object.create(person) | створює об'єкт із заданим прототипом |
JSON.parse() | JSON.parse('{"a":1}') | створює об'єкт із рядка |
Object.assign() | Object.assign({}, obj1, obj2) | копіює та зливає об'єкти |
| Spread-синтаксис | { ...obj1, ...obj2 } | короткий синтаксис копіювання |
Object.fromEntries() | Object.fromEntries([['a', 1]]) | з масиву пар в об'єкт |
Коротко: найпопулярніший спосіб це {}, для спадкування Object.create(), для шаблонів class або функція-конструктор, для копіювання { ...obj } чи Object.assign().
Типові помилки
- Виклик функції-конструктора без
new. У звичайному режиміthisвкаже на глобальний об'єкт і засмітить його, у strict mode будеTypeError. - Очікувати глибоку копію від spread чи
Object.assign(). Обидва копіюють поверхнево: вкладені об'єкти лишаються спільними. Для глибокої копії берітьstructuredClone(). - Використовувати
JSON.parse(JSON.stringify(obj))як універсальний клон. Втрачаються функції,undefined,Dateперетворюється на рядок, а циклічні посилання кидають помилку. - Плутати
Object.create(proto)іnew. Перше просто ставить прототип, друге ще й виконує конструктор. - Створювати методи у фабричній функції для тисяч об'єктів. Кожен екземпляр отримує власну копію функції, тоді як
classтримає одну в прототипі. - Використовувати звичайний
{}як словник для довільних ключів. Ключі на кшталт__proto__абоtoStringконфліктують із прототипом, безпечнішіObject.create(null)абоMap.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.