Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Map проти об'єкта». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Object` це структура загального призначення для властивостей із ключами-рядками або символами, а `Map` це спеціалізована колекція пар «ключ → значення» з ключами будь-якого типу і збереженням порядку вставки.** У `Map` ключем може бути об'єкт чи функція, розмір читається через `.size`, колекція перебирається напряму через `for...of`, вона швидша при частих вставках і видаленнях і не успадковує нічого від `Object.prototype`, тож службові імена не конфліктують із ключами. ```javascript const keyObj = { id: 1 }; const obj = {}; obj[keyObj] = 'object value'; console.log(obj); // { "[object Object]": "object value" } const map = new Map(); map.set(keyObj, 'map value'); console.log(map.get(keyObj)); // "map value" ``` **Ключове:** об'єкт для статичної моделі з відомими полями, `Map` для динамічних колекцій, кешу та ключів довільного типу.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Багато хто вважає, що `Map` і звичайний об'єкт `{}` це майже одне й те саме, але між ними є суттєві відмінності.** `Object` це структура даних загального призначення для зберігання властивостей, ключі яких є рядками або символами, а `Map` це спеціалізована колекція для зберігання пар «ключ → значення» з ключами будь-якого типу і збереженням порядку вставки. ## Теорія ### TL;DR - Ключі об'єкта, це **тільки рядки та символи**, ключі `Map`, це **будь-які значення**. - `Map` завжди повертає елементи **в порядку вставки**, об'єкт сортує цілочислові ключі. - Розмір: `Object.keys(obj).length` проти простого `map.size`. - `Map` ітерабельний напряму через `for...of`, об'єкт, ні. - `Map` швидший при частих вставках і видаленнях. - `Map` не успадковує `Object.prototype`, тож немає конфліктів із `toString` чи `hasOwnProperty`. - Конвертація в обидва боки: `new Map(Object.entries(obj))` і `Object.fromEntries(map)`. ### Швидкий приклад ```javascript const obj = {}; const map = new Map(); const keyObj = { id: 1 }; obj[keyObj] = 'object value'; map.set(keyObj, 'map value'); console.log(obj); // { "[object Object]": "object value" } console.log(map.get(keyObj)); // "map value" ``` В об'єкті ключ перетворився на рядок `"[object Object]"`, а в `Map` залишився **справжнім об'єктом**. Якби ми додали другий об'єкт як ключ, в `obj` він би просто перезаписав перший запис, бо рядок вийшов би той самий. ### Тип ключів | Особливість | `Object` | `Map` | | --- | --- | --- | | Ключі | Тільки рядки або символи | Будь-які типи (рядки, числа, об'єкти, функції тощо) | Це найважливіша практична різниця: лише `Map` дозволяє використати об'єкт або функцію як ключ і таким чином «прив'язати» дані до конкретного екземпляра. ### Порядок, розмір і перебір **Порядок ключів.** | Особливість | `Object` | `Map` | | --- | --- | --- | | Порядок ключів | Частково гарантований (ES6 і новіші) | Завжди зберігається | `Map` завжди повертає елементи **в порядку вставки**, а об'єкт поводиться інакше з числовими ключами: ```javascript const obj = { 2: 'b', 1: 'a' }; console.log(Object.keys(obj)); // ["1", "2"] (числа сортуються за зростанням) ``` ```javascript const map = new Map([[2, 'b'], [1, 'a']]); console.log([...map.keys()]); // [2, 1] (порядок зберігається) ``` **Розмір.** | Особливість | `Object` | `Map` | | --- | --- | --- | | Розмір | `Object.keys(obj).length` | `map.size` | ```javascript const map = new Map([['a', 1], ['b', 2]]); console.log(map.size); // 2 ``` Різниця не лише в зручності: `Object.keys()` створює проміжний масив, а `size` це просто читання лічильника. **Ітерабельність.** | Особливість | `Object` | `Map` | | --- | --- | --- | | Перебирається напряму | Ні | Так | ```javascript const map = new Map([['x', 10], ['y', 20]]); for (const [key, value] of map) { console.log(key, value); } // x 10 // y 20 ``` Для об'єкта доведеться викликати `Object.keys()`, `Object.entries()` і подібні методи. ### Продуктивність і прототип | Особливість | `Object` | `Map` | | --- | --- | --- | | Часті вставки та видалення | Повільніше | Швидше | | Ітерації по елементах | Незручно | Зручно через `for...of` | `Map` оптимізований саме під часті додавання, видалення і обхід, тоді як рушій оптимізує об'єкти під стабільну «форму» з відомим набором полів. | Особливість | `Object` | `Map` | | --- | --- | --- | | Успадковує від `Object.prototype` | Так | Ні | | Може конфліктувати з методами (`toString`, `hasOwnProperty`) | Так | Ні | У `Map` немає «сміття» у вигляді вбудованих методів, тому будь-який ключ можна використовувати безпечно. В об'єкті ключ `"hasOwnProperty"` або `"__proto__"` здатен зламати логіку перевірок. ### Перетворення між ними ```javascript const obj = { a: 1, b: 2 }; const map = new Map(Object.entries(obj)); console.log(map); // Map(2) { 'a' => 1, 'b' => 2 } const backToObj = Object.fromEntries(map); console.log(backToObj); // { a: 1, b: 2 } ``` `Object.entries()` і `Object.fromEntries()` дозволяють легко конвертувати туди й назад. Це ж і спосіб серіалізувати `Map`, бо напряму `JSON.stringify(map)` дає `{}`. ### Що і коли використовувати | Використовуй | Коли | | --- | --- | | `Object` | структура даних із фіксованими властивостями (наприклад, модель користувача) | | `Map` | динамічні ключі, ключі будь-якого типу, кеш, часті операції додавання та видалення | **Коротко:** | Особливість | `Object` | `Map` | | --- | --- | --- | | Тип ключів | рядок або символ | будь-який тип | | Порядок ключів | частково впорядкований | зберігається | | Розмір | треба рахувати вручну | `.size` | | Ітерабельність | через `Object.keys()` | напряму (`for...of`) | | Продуктивність | нижча | вища | | Застосування | статичні дані | динамічні колекції | ### Типові помилки - **Використовувати об'єкт як ключ звичайного об'єкта.** Ключ мовчки стане рядком `"[object Object]"`, і всі об'єкти зіллються в один запис. - **Покладатися на порядок числових ключів об'єкта.** Цілочислові ключі завжди сортуються за зростанням, незалежно від порядку вставки. - **Писати `map.length` або `map['key']`.** Перше це `undefined`, друге створює властивість поза колекцією; правильно, `map.size` і `map.get('key')`. - **Серіалізувати `Map` напряму.** `JSON.stringify(map)` поверне `{}`, спочатку потрібен `Object.fromEntries(map)` або масив із `[...map]`. - **Брати `Map` скрізь «бо швидше».** Для невеликої фіксованої моделі об'єкт зручніший: деструктуризація, скорочений запис, підтримка в JSON. - **Забувати, що `Map` тримає ключі сильно.** Об'єкти-ключі не зникнуть із пам'яті, поки живий сам `Map`, для слабких посилань є `WeakMap`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.