Map

Объект Map содержит пары ключ-значение и сохраняет порядок вставки. Любое значение (как объекты, так и примитивы) могут быть использованы в качестве ключей.

Синтаксис

new Map([iterable])

Параметры

iterable
Массив или любой другой итерируемый объект чьими элементами являются пары ключ-значение (массивы из двух элементов, например [[ 1, 'one' ],[ 2, 'two' ]]). Все пары ключ-значение будут добавлены в новый экземпляр Map; null расценивается как undefined.

Описание

Объект Map итерируется в порядке вставки его элементов — цикл for...of будет возвращать массив [key, value] на каждой итерации.

Key equality

Сравнение ключей основано на алгоритме "SameValueZero": NaN равно NaN (несмотря на то, что NaN !== NaN), все другие значения рассматриваются равными исходя из семантики оператора строгого равенства ===. В текущей спецификации ECMAScript -0 и +0 принимаются равными, но в ранних версиях обсуждения это было не так (см. "Value equality for -0 and 0" в таблице совместимости с браузерами).

Сравнение Объектов и Map

Объекты похожи на Map в том, что оба позволяют устанавливать значения по ключам, получать эти значения, удалять ключи и проверять их наличие. В связи с этим (и потому, что не было встроенных альтернатив), Объекты исторически использовались как Map. Однако, у них есть ряд отличий, который даёт преимущества Map в ряде случаев:

  • Ключами Объекта выступают Строки и Символы, в то время как любое значение может быть ключом Map, включая функции, объекты и примитивы.
  • В отличие от Объектов, ключи в Map упорядочены. Таким образом, во время итерации Map, ключи возвращаются в порядке вставки.
  • Вы легко можете получить количество элементов в Map с помощью свойства size, в то время как количество элементов Объекта может быть определено только вручную.
  • Map - итерируемый объект и может быть итерирован напрямую, в то время как Объект требует ручного получения списка ключей и их итерации.
  • Объект имеет прототип и поэтому имеет стандартный набор ключей, который, при неосторожности, может пересекаться с вашими ключами. С момента выхода ES5 это может быть изменено с помощью map = Object.create(null).
  • Map может иметь более высокую производительность в случаях частого добавления или удаления ключей.

Свойства

Map.length
Значение свойства length всегда равно 0.
Чтобы узнать количество элементов в Map - используйте Map.prototype.size.
get Map[@@species]
Функция-конструктор которая используется для создания производных объектов.
Map.prototype
Представляет прототип конструктора Map. Позволяет добавлять свойства всем объектам типа Map.

Экземпляры Map

Все экземпляры Map наследуются от Map.prototype.

Свойства

Map.prototype.constructor
Возвращает функцию, которая создала прототип экземпляра. Это функция Map по умолчанию.
Map.prototype.size
Возвращает количество пар ключ/значение в объекте Map.

Методы

Map.prototype.clear()
Удаляет все пары ключ / значение из объекта Map.
Map.prototype.delete(key)
Возвращает true, если элемент в объекте Map существовал и был удалён, или false, если элемент не существует. Map.prototype.has(key) вернёт false позже.
Map.prototype.entries()
Возвращает новый объект Iterator который содержит массив [key, value] для каждого элемента в объекте Map в порядке вставки.
Map.prototype.forEach(callbackFn[, thisArg])
Вызывает callbackFn один раз для каждой пары ключ-значение, присутствующей в объекте Map, в порядке вставки. Если для thisArg предоставляется параметр для forEach, он будет использоваться как значение this для каждого колбэка.
Map.prototype.get(key)
Возвращает значение связанное с key, или undefined если его нет.
Map.prototype.has(key)
Возвращает логическое значение, подтверждающее, было ли значение связано с key в объекте Map или нет.
Map.prototype.keys()
Возвращает новый объект Iterator содержащий ключи для каждого элемента в объекте Map в порядке вставки.
Map.prototype.set(key, value)
Устанавливает значение для key в объекте Map. Возвращает объект Map.
Map.prototype.values()
Возвращает новый объект Iterator который содержит значения для каждого элемента в объекте Map в порядке вставки.
Map.prototype[@@iterator]()
Возвращает новый объект Iterator который содержит массив [key, value] для каждого элемента в объекте Map в порядке вставки.

Примеры

Использование объекта Map

const myMap = new Map();

const keyObj = {},
    keyFunc = function () {},
    keyString = 'a string';

// задание значений
myMap.set(keyString, 'value associated with “a string”');
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');

myMap.size; // 3

// получение значений
myMap.get(keyString);    // value associated with “a string”
myMap.get(keyObj);       // value associated with keyObj
myMap.get(keyFunc);      // value associated with keyFunc

myMap.get('a string');   // "value associated with 'a string'"
                         // потому что keyString === 'a string'
myMap.get({});           // undefined, потому что keyObj !== {} ({} — это литеральная нотация конструктора класса Object)
myMap.get(function() {}) // undefined, потому что keyFunc !== function () {}

Использование NaN в качестве ключей Map

NaN может быть использован в качестве ключа. Несмотря на то, что NaN не равен самому себе (NaN !== NaN вернёт true), следующий пример работает, потому что NaN обрабатывается особым образом:

const myMap = new Map();
myMap.set(NaN, 'not a number');

myMap.get(NaN); // not a number

const otherNaN = Number('foo');
myMap.get(otherNaN); // not a number

Итерация Map при помощи for..of

Map может быть итерирован с помощью for..of:

const myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');
for (var [key, value] of myMap) {
  console.log(key + ' = ' + value);
}
// 0 = zero
// 1 = one

for (var key of myMap.keys()) {
  console.log(key);
}
// 0
// 1

for (var value of myMap.values()) {
  console.log(value);
}
// zero
// one

for (var [key, value] of myMap.entries()) {
  console.log(key + ' = ' + value);
}
// 0 = zero
// 1 = one

Итерация Map при помощи forEach()

Map может быть итерирован с помощью метода forEach():

myMap.forEach(function(value, key) {
  console.log(`${key} => ${value}`);
});
// 0 => zero
// 1 => one

Взаимоотношения с объектом Array

const kvArray = [['key1', 'value1'], ['key2', 'value2']];

// Используйте конструктор Map для преобразования двумерных массивов в Map
const myMap = new Map(kvArray);

myMap.get('key1'); // вернёт “value1”

// Используйте функцию Array.from для трансформации Map в двумерный key-value массив
console.log(Array.from(myMap)); // Выведет точно такой же массив как kvArray

// Или используйте итераторы  keys или values чтобы преобразовать ключи или значения в массивы
console.log(Array.from(myMap.keys())); // Выведет ['key1', 'key2']

Клонирование и слияние Map

 Равно как и Массивы, Map могут быть клонированы:

const original = new Map([
  [1, 'one']
]);

const clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false.

Следует помнить, что данные не клонируются.

Map могут быть слиты, с сохранением уникальности ключей:

const first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

const second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// Слияние двух Map. Взят будет последний повторившийся ключ.
// Оператор Spread по сути преобразует Map в массив
const merged = new Map([...first, ...second]);

console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

Map могут быть слиты и с Массивами:

const first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

const second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// Слияние Map и массива. Как и при слиянии двух Map - взят будет последний повторившийся ключ.
const merged = new Map([...first, ...second, [1, 'eins']]);

console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

Спецификации

Спецификация Статус Комментарий
ECMAScript 2015 (6th Edition, ECMA-262)
Определение 'Map' в этой спецификации.
Стандарт Initial definition.
ECMAScript (ECMA-262)
Определение 'Map' в этой спецификации.
Живой стандарт

Совместимость с браузерами

BCD tables only load in the browser

Смотрите также