Колекція Map у JavaScript
Map це вбудований об'єкт JavaScript, який зберігає пари «ключ, значення» і запам'ятовує порядок вставки цих пар. Він схожий на звичайний об'єкт {}, але має розширені можливості: ключем може бути будь-який тип даних, є зручні методи для додавання, видалення та перебору, і порядок елементів гарантований.
Теорія
TL;DR
Mapце колекція пар «ключ, значення» з гарантованим порядком вставки.- Ключем може бути будь-що: рядок, число, об'єкт, функція, навіть
NaN. - Ключі-об'єкти порівнюються за посиланням, а не за рядковим представленням.
- Методи:
set,get,has,delete,clear, плюс властивістьsize. - Колекція ітерована:
for...of,.forEach(),.keys(),.values(),.entries(). - Конвертація в обидва боки:
new Map(Object.entries(obj))іObject.fromEntries(map).
Швидкий приклад
const map = new Map();
map.set('name', 'Alex');
map.set('age', 25);
console.log(map.get('name')); // Alex
console.log(map.get('age')); // 25
console.log(map.size); // 2Основні методи та властивості
| Метод / властивість | Що робить | Приклад |
|---|---|---|
set(key, value) | Додає елемент | map.set('a', 1) |
get(key) | Повертає значення за ключем | map.get('a') |
has(key) | Перевіряє наявність ключа | map.has('a') // true |
delete(key) | Видаляє елемент | map.delete('a') |
clear() | Очищає всю колекцію | map.clear() |
size | Кількість елементів | map.size // 2 |
set() повертає сам Map, тому виклики можна зв'язувати в ланцюжок: map.set('a', 1).set('b', 2).
Ключі будь-якого типу
const map = new Map();
const objKey = { id: 1 };
const funcKey = () => {};
const numKey = 42;
map.set(objKey, 'object');
map.set(funcKey, 'function');
map.set(numKey, 'number');
console.log(map.get(objKey)); // object
console.log(map.get(funcKey)); // function
console.log(map.get(42)); // numberНа відміну від звичайного об'єкта {}, ключі тут порівнюються за посиланням, а не за приведеною до рядка формою. Тому { id: 1 } і новий літерал { id: 1 } це два різні ключі.
Навіть NaN працює як ключ, що в звичайних об'єктах неможливо:
const map = new Map();
map.set(NaN, 'Not a Number');
console.log(map.get(NaN)); // 'Not a Number'Перебір Map
Map це ітерована колекція, тож обійти її можна кількома способами.
for...of:
const map = new Map([
['name', 'Alex'],
['age', 25],
]);
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// name: Alex
// age: 25- Метод
forEach(зверніть увагу на порядок аргументів: спочатку значення, потім ключ):
map.forEach((value, key) => {
console.log(key, value);
});- Окремо ключі, значення або записи:
console.log([...map.keys()]); // ['name', 'age']
console.log([...map.values()]); // ['Alex', 25]
console.log([...map.entries()]); // [['name','Alex'], ['age',25]]Map проти звичайного об'єкта
| Особливість | Object | Map |
|---|---|---|
| Тип ключів | Тільки рядок або символ | Будь-який тип, включно з об'єктами та функціями |
| Порядок елементів | Не гарантований (до ES2015) | Гарантований |
| Кількість елементів | Треба рахувати вручну (Object.keys().length) | map.size |
| Видалення | delete obj.key (повільно) | map.delete(key) (швидко) |
| Перебір | for...in (разом з успадкованими властивостями) | Чистий for...of |
| Продуктивність | Краще для невеликих наборів даних | Краще для частих вставок і видалень |
Конвертація та практичне застосування
З об'єкта в Map:
const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));З Map в об'єкт:
const obj2 = Object.fromEntries(map);Лічильник входжень елементів, класичний випадок для Map:
const arr = ['a', 'b', 'a', 'c', 'b', 'a'];
const counter = new Map();
for (const item of arr) {
counter.set(item, (counter.get(item) || 0) + 1);
}
console.log(counter); // Map(3) { 'a' => 3, 'b' => 2, 'c' => 1 }Беріть Map, якщо:
- потрібно зберігати не тільки рядки як ключі;
- важливо зберігати порядок вставки;
- потрібні часті додавання та видалення елементів;
- ви працюєте з асоціативними структурами даних.
Коротке резюме:
| Що | Опис |
|---|---|
| Тип | Колекція «ключ, значення» |
| Ключі | Будь-які типи, включно з об'єктами |
| Порядок | Зберігається |
| Методи | .set(), .get(), .has(), .delete(), .clear() |
| Розмір | map.size |
| Перебір | for...of, .forEach(), .keys(), .values(), .entries() |
Типові помилки
- Звертатися до
Mapяк до об'єкта.map['name']створить звичайну властивість на об'єктіMap, а не запис у колекції;map.get('name')повернеundefined. - Чекати на
map.length. УMapнемаєlength, єsize, і це властивість, а не метод. - Використовувати новий літерал об'єкта як ключ для пошуку.
map.set({ id: 1 }, x)іmap.get({ id: 1 })це різні посилання, тому результат будеundefined. - Плутати порядок аргументів у
forEach. Колбек отримує(value, key, map), а не(key, value). - Серіалізувати
MapчерезJSON.stringify. Результат буде{}; спочатку перетворіть колекцію на об'єкт або масив, наприкладObject.fromEntries(map). - Тримати об'єкти-ключі в
Mapі чекати, що їх прибере збирач сміття.Mapтримає сильні посилання; для слабких потрібенWeakMap.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.