Map – коллекция пар ключ-значение.
Объект содержит пары ключ-значение и запоминает исходный порядок вставки ключей. Любое значение (как объекты, так и примитивные значения) может использоваться либо как ключ, либо как значение.
Map хранит в себе данные, где в виде ключа могут быть: строки, цифры, булево значение.
Например:
let map = new Map()
map.set("1", "str1") // строка в качестве ключа
map.set(1, "num1") // цифра как ключ
map.set(true, "bool1") // булево значение как ключ
// помните, обычный объект Object приводит ключи к строкам? // Map сохраняет тип ключей, так что в этом случае сохранится 2 разных значения:
alert(map.get(1)) // "num1"
alert(map.get("1")) // "str1"
alert(map.size) // 3`
Методы и свойства:
new Map([iterable])
– создаёт коллекцию, можно указать перебираемый объект (обычно массив) из пар[ключ,значение]
для инициализации.map.set(key, value)
– записывает по ключуkey
значениеvalue
.map.get(key)
– возвращает значение по ключу илиundefined
, если ключkey
отсутствует.map.has(key)
– возвращаетtrue
, если ключkey
присутствует в коллекции, иначеfalse
.map.delete(key)
– удаляет элемент по ключуkey
.map.clear()
– очищает коллекцию от всех элементов.map.size
– возвращает текущее количество элементов.
Отличия от обычного объекта Object
:
- Что угодно может быть ключом, в том числе и объекты.
- Есть дополнительные методы, свойство
size
. Как мы видим, в отличие от объектов, ключи не были приведены к строкам. Можно использовать любые типы данных для ключей.
Особенности использования map[key]
map[key]
это не совсем правильный способ использования Map
Хотя map[key]
также работает, например, мы можем установить map[key] = 2
, в этом случаеmap
рассматривался бы как обычный JavaScript объект, таким образом это ведёт ко всем соответствующим ограничениям (только строки/символьные ключи и так далее).
Поэтому нам следует использовать методы map
: set
, get
и так далее.
Map может использовать объекты в качестве ключей
Например:
let john = { name: "John" }; // давайте сохраним количество посещений для каждого пользователя let visitsCountMap = new Map(); // объект john - это ключ для значения в объекте
Map visitsCountMap.set(john, 123);
alert(visitsCountMap.get(john)); // 123`
Использование объектов в качестве ключей – одна из наиболее заметных и важных функций Map
. Это то что невозможно для Object
. Строка в качестве ключа в Object
– это нормально, но мы не можем использовать другой Object
в качестве ключа в Object
.
Давайте попробуем заменить Map
на Object
:
let john = { name: "John" }
let ben = { name: "Ben" }
let visitsCountObj = {} // попробуем использовать объект visitsCountObj[ben] = 234; // пробуем использовать объект ben в качестве ключа visitsCountObj[john] = 123; // пробуем использовать объект john в качестве ключа, при этом объект ben будет замещён _// Вот что там было записано!
alert(visitsCountObj["[object Object]"]) // 123_`
Так как visitsCountObj
является объектом, он преобразует все ключи Object
, такие как john
и ben
, в одну и ту же строку "[object Object]"
. Это определенно не то, чего мы хотим.
Как объект Map
сравнивает ключи
Чтобы сравнивать ключи, объект Map
использует алгоритм SameValueZero. Это почти такое же сравнение, что и === , с той лишь разницей, что NaN
считается равным NaN
. Так что NaN
также может использоваться в качестве ключа.
Этот алгоритм не может быть заменён или модифицирован.
Цепочка вызовов
Каждый вызов map.set
возвращает объект map, так что мы можем объединить вызовы в цепочку:
map.set("1", "str1")
.set(1, "num1")
.set(true, "bool1");`
Для перебора коллекции Map
есть 3 метода:
map.keys()
– возвращает итерируемый объект по ключам,map.values()
– возвращает итерируемый объект по значениям,map.entries()
– возвращает итерируемый объект по парам вида[ключ, значение]
, этот вариант используется по умолчанию вfor..of
.
Например:
let recipeMap = new Map([
["огурец", 500],
["помидор", 350],
["лук", 50],
])
// перебор по ключам (овощи)
for (let vegetable of recipeMap.keys()) {
alert(vegetable) // огурец, помидор, лук
} // перебор по значениям (числа)
for (let amount of recipeMap.values()) {
alert(amount) // 500, 350, 50
} // перебор по элементам в формате [ключ, значение]
for (let entry of recipeMap) {
// то же самое, что и recipeMap.entries()
alert(entry) // огурец,500 (и так далее)
}
Используется порядок вставки
В отличие от обычных объектов Object
, в Map
перебор происходит в том же порядке, в каком происходило добавление элементов.
Кроме этого, Map
имеет встроенный метод forEach
, схожий со встроенным методом массивов Array
:
// выполняем функцию для каждой пары (ключ, значение)
recipeMap.forEach((value, key, map) => {
alert(`${key}: ${value}`); // огурец: 500 и так далее });``