Set и Map
Set и Map
Технический фундамент структур данных
Set и Map это не просто "удобные контейнеры", а отдельные структуры со своими свойствами:
Setпроверяет уникальность по алгоритмуSameValueZero(например,NaNсчитается равнымNaN);Mapхранит соответствие ключа значению и сохраняет порядок вставки;- обе структуры итерируемы и хорошо подходят для частых операций поиска/проверки.
Понимание этих деталей помогает выбирать структуру не по привычке, а по требованиям к данным и операциям.
Зачем нужны Set и Map, если уже есть массивы и объекты
Массивы и объекты покрывают много задач, но не все. Когда тебе нужна коллекция уникальных значений, массив неудобен: приходится вручную проверять дубли. Когда нужен словарь с ключами не только-строками, обычный объект тоже ограничивает. Set и Map решают эти проблемы на уровне встроенных структур данных.
Ключевой момент: Set хранит уникальные значения, а Map хранит пары ключ -> значение с гибкими типами ключей.
Проверь себя: почему хранить уникальные ID пользователей в Set часто проще, чем в массиве?
Set: коллекция без дублей
Set автоматически игнорирует повторяющиеся значения.
const tags = new Set(['js', 'ts', 'js']);
console.log(tags.size); // 2
console.log(tags.has('ts')); // true
tags.add('node');
tags.delete('js');
Смотри, что важно: в Set нет индексов как в массиве. Ты работаешь через методы add, has, delete, size.
Мини-сценарий: убрать дубликаты email перед массовой отправкой.
const emails = ['a@mail.com', 'b@mail.com', 'a@mail.com'];
const uniqueEmails = [...new Set(emails)];
console.log(uniqueEmails); // ['a@mail.com', 'b@mail.com']
Map: словарь с гибкими ключами
Map хранит пары и позволяет использовать в ключах не только строки.
const userVisits = new Map();
userVisits.set('user-1', 3);
userVisits.set('user-2', 7);
console.log(userVisits.get('user-2')); // 7
console.log(userVisits.has('user-3')); // false
Главное отличие от объекта: ключом в Map может быть объект, функция, число и т.д.
const cache = new Map();
const request = { path: '/profile' };
cache.set(request, { ok: true });
console.log(cache.get(request)); // { ok: true }
Смотри, что важно: объект-ключ в Map сравнивается по ссылке, а не "по содержимому". Два одинаковых объекта это два разных ключа.
const map = new Map();
map.set({ id: 1 }, 'saved');
console.log(map.get({ id: 1 })); // undefined (другая ссылка)
Смотри, что важно: map.get(key) возвращает undefined, если ключа нет. Но undefined может быть и реальным значением, поэтому для точной проверки используй has.
const m = new Map();
m.set('x', undefined);
console.log(m.get('x')); // undefined
console.log(m.has('x')); // true
console.log(m.get('y')); // undefined
console.log(m.has('y')); // false
Когда выбирать Set, а когда Map
Set- когда нужно хранить уникальные элементы без дополнительных значений.Map- когда каждой сущности нужно сопоставить значение (счетчик, статус, данные).
Пример из продукта:
Setдля списка активных сокетов без дублей;Mapдля хранения количества действий поuserId.
Проверь себя: если нужно хранить productId -> quantity, подойдет Set или Map?
Итерация по Set и Map
Обе структуры итерируемы через for...of.
const statuses = new Set(['new', 'paid', 'done']);
for (const status of statuses) {
console.log(status);
}
const ratings = new Map([
['p1', 4.8],
['p2', 4.3],
]);
for (const [id, value] of ratings) {
console.log(id, value);
}
Дополнительный пример: агрегатор частоты значений через Map.
function countBy(items) {
const counter = new Map();
for (const item of items) {
counter.set(item, (counter.get(item) ?? 0) + 1);
}
return counter;
}
Здесь часто путаются: у Map элемент итерации это пара [key, value].
Частые ошибки новичков
- Использовать
Setи ждать доступа по индексу. - Пытаться читать из
Mapчерезmap.keyвместоmap.get(key). - Забывать, что объекты-ключи в
Mapсравниваются по ссылке. - Применять
Set/Mapтам, где простой массив/объект действительно достаточно.
Анти-провал: сначала сформулируй задачу коллекции (уникальность или пары ключ-значение), и только потом выбирай структуру.
Что будет, если изменить входные данные
Если в Set добавить одно и то же значение 10 раз, размер не увеличится после первого добавления. Если в Map повторно вызвать set с тем же ключом, старое значение перезапишется. Это предсказуемая логика, которая часто нужна в кэше и агрегаторах.
Проверь себя: что вернет map.get('missing-key') и почему это полезно при проверках?
Краткий итог
Setхранит только уникальные значения и удобен для дедупликации.Mapхранит парыключ -> значениеи поддерживает любые типы ключей.- Оба типа итерируемы и имеют предсказуемые методы работы с данными.
- Выбор структуры должен исходить из задачи, а не из "модности" API.
- Правильное использование
Set/Mapснижает количество ручных проверок и упрощает код.