Способи оголосити об'єкт
У JavaScript є кілька способів створити об'єкт, і вибір залежить від того, що саме потрібно: простий об'єкт, копія, шаблон чи екземпляр класу. Усі вони дають той самий тип даних, але відрізняються тим, як задається прототип і скільки шаблонного коду доводиться писати.
Теорія
TL;DR
- Літерал
{}це найкоротший і найчастіший спосіб у реальному коді. new Object()робить те саме, але довше, тому його майже не використовують.Object.create(proto)створює об'єкт із заданим прототипом.- Функція-конструктор з
newіclassстворюють екземпляри певного «типу». - Spread (
{ ...base }) створює копію наявного об'єкта з новими властивостями. Object.fromEntries()збирає об'єкт із пар «ключ -> значення».
Швидкий приклад
const user = {
name: 'Tim',
age: 25
};Літерал створює новий об'єкт одразу з потрібними властивостями. Це найпоширеніший спосіб у реальному коді: коротко, читабельно і без зайвих церемоній.
Літерал і конструктор Object
Через конструктор той самий об'єкт виглядає так:
const user = new Object();
user.name = 'Tim';
user.age = 25;Спосіб робочий, але зазвичай не рекомендований: літерали ({}) коротші й зрозуміліші, а результат виходить ідентичним. new Object() зустрічається хіба що в старому коді або заради сумісності.
Object.create(proto)
Цей спосіб дозволяє створити об'єкт із визначеним прототипом:
const person = { species: 'human' };
const user = Object.create(person);
user.name = 'Tim';
console.log(user.species); // "human" (успадковано від person)Його використовують у просунутих сценаріях, коли потрібно вручну керувати ланцюжком прототипів. Окремий корисний випадок це Object.create(null): об'єкт зовсім без прототипу, зручний як словник.
Функція-конструктор і class
Функції-конструктори (виклик з new) створюють об'єкти певного «типу» і автоматично встановлюють this на новий об'єкт:
function User(name, age) {
this.name = name;
this.age = age;
}
const tim = new User('Tim', 25);
console.log(tim.name); // "Tim"class це синтаксичний цукор над функцією-конструктором, і саме його використовують у сучасному JS:
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const tim = new User('Tim', 25);
console.log(tim.name); // "Tim"Обидва варіанти дають екземпляри зі спільним прототипом, тому методи зберігаються один раз, а не копіюються в кожен об'єкт.
Spread і Object.fromEntries()
Spread створює копію наявного об'єкта з додаванням нових властивостей:
const base = { role: 'user' };
const user = { ...base, name: 'Tim', age: 25 };Object.fromEntries() збирає об'єкт із масиву пар, що корисно після Object.entries() або під час роботи з Map:
const entries = [['name', 'Tim'], ['age', 25]];
const user = Object.fromEntries(entries);
console.log(user); // { name: 'Tim', age: 25 }Підсумкова таблиця
| Спосіб | Приклад | Коли використовувати |
|---|---|---|
Літерал {} | { name: 'Tim' } | найчастіший спосіб |
new Object() | new Object() | рідко, заради сумісності |
Object.create(proto) | Object.create(person) | потрібне керування прототипом |
| Функція-конструктор | new User() | старий, але робочий підхід |
class | new User() | сучасний, ООП-підхід |
| Spread, копія | { ...obj } | дублювання і розширення об'єктів |
Object.fromEntries() | Object.fromEntries(pairs) | створення з пар «ключ -> значення» |
Якщо стисло: об'єкт у JS можна створити різними способами, від простого {} до class, але у 95% випадків достатньо літерала {} або class для структурованих даних.
Типові помилки
- Писати
new Object()замість{}. Результат той самий, але коду більше, а читабельності менше. - Плутати
Object.create(person)з копіюванням. Властивостіpersonне копіюються, вони успадковуються, тому зміна прототипу відразу видно в усіх нащадках. - Викликати функцію-конструктор без
new. Тодіthisне буде новим об'єктом, функція повернеundefined, а в нестрогому режимі ще й зіпсує глобальний об'єкт. - Вважати
{ ...base }глибокою копією. Spread копіює тільки верхній рівень, вкладені об'єкти залишаються спільними. - Чекати від spread копіювання прототипу. Розкладаються лише власні перелічувані властивості, тому екземпляр класу після spread стає звичайним об'єктом без методів.
- Використовувати звичайний об'єкт як словник для довільних ключів. Ключі на кшталт
constructorабоtoStringконфліктують із прототипом; тут доречнішіObject.create(null)абоMap.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.