JavaScript Map: хранение и поиск пар ключ-значение
Объект JavaScript Map хранит пары ключ-значение и позволяет использовать в роли ключа любое значение: объект, функцию или примитив. Используйте его, когда нужен обход в порядке вставки, ключи не только строкового типа или частые добавления и удаления. В отличие от обычных объектов, ключи Map не зависят от унаследованных свойств прототипа, поэтому динамические строковые ключи ведут себя предсказуемо.
Пример JavaScript Map для хранения пар ключ-значение
Вывод:
Результат появится здесь...
Вывод:
95
false
2
Как работает этот пример
new Map()создает пустую коллекцию map. ВызовMap()безnewвызываетTypeError.setдобавляет пару ключ-значение и возвращает экземплярMap, поэтому можно делать цепочки вызовов, напримерmap.set("a", 1).set("b", 2). Если вызватьsetс существующим ключом, значение перезапишется без изменения позиции ключа в порядке обхода.getвозвращает сохраненное значение илиundefined, если ключа нет. Используйтеhas, чтобы отличить отсутствующий ключ от ключа, который явно записан со значениемundefined.sizeпоказывает текущее количество записей, в отличие от объектов, где нужно вычислятьObject.keys(obj).length.
Частые ошибки при использовании JavaScript Map
Использование синтаксиса скобок вместо set/get:
Неправильно:
const map = new Map();
map["ключ"] = "значение";
console.log(map.get("ключ")); // undefined
Правильно:
const map = new Map();
map.set("ключ", "значение");
console.log(map.get("ключ")); // "значение"
Синтаксис скобок задает свойство объекта у экземпляра Map, а не запись Map. Методы get, has и свойство size это игнорируют.
Ожидание структурного равенства для ключей-объектов:
Неправильно:
const map = new Map();
map.set({id: 1}, "анна");
console.log(map.get({id: 1})); // undefined
Правильно:
const key = {id: 1};
map.set(key, "анна");
console.log(map.get(key)); // "анна"
Map использует алгоритм SameValueZero для сравнения ключей. Для объектов это означает сравнение по ссылке: два одинаковых на вид объектных литерала считаются разными ключами.
JavaScript Map vs Object
Map | Object | |
|---|---|---|
| Типы ключей | Любые значения (объекты, функции, примитивы) | Только строки и символы |
| Порядок обхода | Порядок вставки (гарантирован) | В основном порядок вставки, но целочисленные ключи сортируются первыми |
| Размер | map.size | Object.keys(obj).length |
| Коллизии с прототипом | Нет | Ключи могут перекрыть toString, constructor и т. д. |
| JSON-сериализация | Вручную через Object.fromEntries | Встроено в JSON.stringify |
Используйте Map, когда ключи не строки, записи часто добавляются и удаляются или вы храните недоверенные ключи. Используйте обычный объект для записей с фиксированной структурой или данных, которым нужна сериализация в JSON.
Если нужен объект, но вы хотите избежать коллизий с ключами прототипа, используйте Object.create(null) как базовый объект.
FAQ
Сохраняет ли JavaScript Map порядок вставки?
Да. Map итерирует записи в порядке их первого добавления. Вызов set() для существующего ключа обновляет значение, но сохраняет исходную позицию. Если удалить ключ и добавить его снова, он переместится в конец.
Можно ли использовать объекты как ключи в JavaScript Map?
Да, но Map сравнивает ключи-объекты по ссылке, а не по структуре. Два разных объекта с одинаковыми свойствами считаются разными ключами. Сохраните ссылку в переменную и используйте одну и ту же ссылку в set и get.
Как преобразовать JavaScript Map в объект или JSON?
Вызовите Object.fromEntries(map), чтобы получить обычный объект, это работает, когда все ключи строки или символы. Для нестроковых ключей сериализуйте массив записей: JSON.stringify([...map]).
В чем разница между JavaScript Map и функцией JavaScript map()?
Map это коллекция ключ-значение для хранения и получения данных. Функция JavaScript map() (Array.prototype.map) это метод массива, который возвращает новый массив, применяя колбэк к каждому элементу. Название общее, назначение разное.