</> Praktum

Главная / JavaScript / Map и Set

Справочник · JavaScript

Map и Set: коллекции в JavaScript

Редакция PraktumОбновлено 5 мин чтенияУровень: новичок

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;              // 2

Set убирает повторы, Map хранит пары с удобными методами. Оба можно сразу заполнить при создании: new Set(массив), new Map([[ключ, значение], …]).

Методы Map и Set

Основные методы
MapSetЧто делает
set(k, v)add(v)добавить
get(k)—получить значение
has(k)has(v)проверить наличие
delete(k)delete(v)удалить
clear()clear()очистить
sizesizeколичество
keys(), values(), entries()values()перебор

Map или объект

Сравнение
MapObject
Типы ключейлюбыестроки и символы
Размерmap.sizeObject.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 или массив

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 с ключами-объектами, который не мешает сборке мусора.

Источники

Ещё в разделе JavaScript