Справочник · JavaScript
Map и Set: коллекции в JavaScript
Map хранит пары «ключ — значение», где ключом может быть что угодно: строка, число, объект, DOM-элемент. Set хранит набор уникальных значений без повторов. Обе коллекции помнят порядок добавления, знают свой размер через size и перебираются через for...of. Самый частый приём — убрать дубликаты из массива: [...new Set(arr)].
new Map()— set, get, has, delete, size.- Ключом Map может быть объект или элемент.
new Set(arr)— только уникальные значения.- Без дубликатов:
[...new Set(arr)]. - Порядок добавления сохраняется.
Минимальный пример
const tags = ['css', 'html', 'css', 'js', 'html'];
const unique = [...new Set(tags)]; // ['css', 'html', 'js']
const prices = new Map();
prices.set('Кроссовки', 5990);
prices.set('Носки', 390);
prices.get('Носки'); // 390
prices.has('Кепка'); // false
prices.size; // 2Set убирает повторы, Map хранит пары с удобными методами. Оба можно сразу заполнить при создании: new Set(массив), new Map([[ключ, значение], …]).
Методы Map и Set
| Map | Set | Что делает |
|---|---|---|
set(k, v) | add(v) | добавить |
get(k) | — | получить значение |
has(k) | has(v) | проверить наличие |
delete(k) | delete(v) | удалить |
clear() | clear() | очистить |
size | size | количество |
keys(), values(), entries() | values() | перебор |
Map или объект
| Map | Object | |
|---|---|---|
| Типы ключей | любые | строки и символы |
| Размер | map.size | Object.keys(obj).length |
| Порядок | порядок добавления | числовые ключи сортируются первыми |
| Частые добавления и удаления | оптимизирован | медленнее |
| JSON | нужно преобразовать | напрямую |
Для фиксированной структуры данных (пользователь, настройки) удобнее объект. Для словаря, который часто меняется, или ключей-объектов — Map.
Map как индекс для быстрого поиска
const byId = new Map(products.map((p) => [p.id, p]));
byId.get(42); // мгновенно, без перебора массива
// подсчёт количества
const counts = new Map();
for (const word of words) {
counts.set(word, (counts.get(word) ?? 0) + 1);
}Если по массиву часто ищут элемент по id, один раз построенный Map делает поиск мгновенным вместо find при каждом обращении. Map удобен и для подсчёта частоты.
DOM-элементы как ключи
const state = new WeakMap();
document.querySelectorAll('.accordion').forEach((el) => {
state.set(el, { open: false });
});
function toggle(el) {
const s = state.get(el);
s.open = !s.open;
}Связать данные с элементом без data-атрибутов позволяет Map или WeakMap. WeakMap не мешает сборщику мусора: когда элемент удалён из страницы и на него нет ссылок, запись исчезает сама. Ключами WeakMap могут быть только объекты.
Операции с множествами
const a = new Set(['html', 'css', 'js']);
const b = new Set(['js', 'react']);
a.union(b); // Set {html, css, js, react}
a.intersection(b); // Set {js}
a.difference(b); // Set {html, css}
// запасной вариант
const common = [...a].filter((x) => b.has(x));Новые методы Set — union, intersection, difference — поддерживаются в актуальных браузерах. В старых окружениях операции делают через filter и has. has у Set работает мгновенно, в отличие от includes у массива.
Map и Set в JSON
JSON.stringify(new Map([['a', 1]])); // '{}' — данные потеряны
JSON.stringify(Object.fromEntries(map)); // '{"a":1}'
JSON.stringify([...set]); // массив
const restored = new Map(Object.entries(JSON.parse(json)));JSON.stringify не умеет сериализовать Map и Set — получится пустой объект. Преобразуй их в объект или массив перед сохранением в localStorage или отправкой на сервер.
Set или массив
Уникальные значения и быстрые проверки has: выбранные фильтры, посещённые id.
Порядок и повторы важны, нужны индексы, map и filter.
Частые ошибки
- Сохраняют Map в JSON напрямую и теряют данные.
- Используют map[key] вместо map.get(key).
- Ищут в массиве через includes в цикле вместо Set.has.
- Используют объект с ключами-элементами — они превращаются в строку '[object HTMLDivElement]'.
- Ждут, что Set уберёт одинаковые по содержимому объекты — он сравнивает ссылки.
Доступность
Map и Set — структуры данных и не влияют на доступность напрямую. Если по ним строится интерфейс (выбранные фильтры), показывай состояние и в разметке: aria-pressed у кнопок фильтров, счётчик выбранного текстом.
Поддержка браузерами
Map, Set, WeakMap и WeakSet поддерживаются всеми актуальными браузерами. Методы union, intersection и difference у Set — в актуальных версиях браузеров.
Практика
Есть массив заказов { userId, total }. Посчитай через Map сумму заказов каждого пользователя, а через Set — количество уникальных покупателей. Выведи пользователя с наибольшей суммой.
Показать решение
const sums = new Map();
for (const { userId, total } of orders) {
sums.set(userId, (sums.get(userId) ?? 0) + total);
}
const buyers = new Set(orders.map((o) => o.userId)).size;
let top = null;
for (const [userId, sum] of sums) {
if (!top || sum > top.sum) top = { userId, sum };
}
console.log(`Покупателей: ${buyers}, лучший: ${top?.userId} (${top?.sum} ₽)`);Частые вопросы
Как убрать дубликаты из массива?
[...new Set(arr)].
Чем Map отличается от объекта?
Ключи Map могут быть любого типа, есть size и сохранён порядок добавления.
Как узнать размер Map или Set?
Свойство size.
Как сохранить Map в JSON?
Преобразуй в объект: Object.fromEntries(map).
Что такое WeakMap?
Map с ключами-объектами, который не мешает сборке мусора.