Spec-Zone.ru › JavaScript

Map

Базовый уровень Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и в различных версиях браузеров. Она доступна во всех браузерах с июля 2015 года.

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

Попробуйте

const map = new Map();

map.set("a", 1);
map.set("b", 2);
map.set("c", 3);

console.log(map.get("a"));
// Expected output: 1

map.set("a", 97);

console.log(map.get("a"));
// Expected output: 97

console.log(map.size);
// Expected output: 3

map.delete("b");

console.log(map.size);
// Expected output: 2

Описание

Объекты Map представляют собой коллекции пар ключ-значение. Ключ в Map может встречаться только один раз; он уникален в коллекции Map. Объект Map итерируется по парам ключ-значение — цикл for...of возвращает массив из 2 элементов [key, value] для каждой итерации. Итерация происходит в порядке вставки, который соответствует порядку, в котором каждая пара ключ-значение была впервые вставлена в Map с помощью метода set() (то есть, когда вызывался set(), ключа с таким же значением еще не было в Map).

Спецификация требует, чтобы реализация Map «в среднем обеспечивала время доступа, которое является сублинейным относительно числа элементов в коллекции». Следовательно, она может быть представлена внутри как хеш-таблица (с поиском O(1)), дерево поиска (с поиском O(log(N))) или любая другая структура данных, при условии, что сложность лучше, чем O(N).

Равенство ключей

Равенство значений основано на алгоритме SameValueZero. (Раньше использовался SameValue, который рассматривал 0 и -0 как разные. Проверьте совместимость с браузерами.) Это означает, что NaN считается тем же, что и NaN (хотя NaN !== NaN), а все остальные значения считаются равными в соответствии с семантикой оператора ===. Кроме того, для ключей-объектов равенство основано на идентичности объекта. Они сравниваются по ссылке, а не по значению. Примеры см. в разделе Использование объекта Map.

Объекты (Objects) против Map

Object похож на Map—оба позволяют устанавливать ключи для значений, извлекать эти значения, удалять ключи и определять, хранится ли что-либо по ключу. По этой причине (и из-за отсутствия встроенных альтернатив) Object исторически использовался как Map.

Однако есть важные различия, которые делают Map предпочтительным в некоторых случаях:

Map Object
Случайные ключи Map по умолчанию не содержит никаких ключей. Он содержит только то, что явно в него помещено.

Объект Object имеет прототип, поэтому он содержит ключи по умолчанию, которые могут конфликтовать с вашими собственными ключами, если вы не будете осторожны.

Примечание: Это можно обойти, используя Object.create(null), но это делается редко.

Безопасность Map безопасно использовать с предоставленными пользователем ключами и значениями.

Установка предоставленных пользователем пар ключ-значение в Object может позволить злоумышленнику переопределить прототип объекта, что может привести к атакам внедрения объекта или атакам загрязнения прототипа. Как и проблему случайных ключей, это также можно смягчить, используя объект с null-прототипом.

Типы ключей Ключи Map могут быть любым значением (включая функции, объекты или любой примитив). Ключи Object должны быть либо String, либо Symbol.
Порядок ключей

Ключи в Map упорядочены простым образом: объект Map итерирует записи, ключи и значения в порядке вставки записи.

Хотя ключи обычного Object теперь упорядочены, так было не всегда, и порядок является сложным. В результате лучше не полагаться на порядок свойств.

Порядок был впервые определён только для собственных свойств в ECMAScript 2015; ECMAScript 2020 также определяет порядок для унаследованных свойств. Но обратите внимание, что ни один механизм не итерирует все свойства объекта; различные механизмы включают разные подмножества свойств. (for-in включает только перечисляемые свойства с ключами-строками; Object.keys включает только собственные, перечисляемые свойства с ключами-строками; Object.getOwnPropertyNames включает собственные свойства с ключами-строками, даже если они неперечисляемые; Object.getOwnPropertySymbols делает то же самое только для свойств с Symbol-ключами и т.д.)

Размер

Количество элементов в Map легко получить из его свойства size. Определение количества элементов в Object более сложно и менее эффективно. Обычный способ сделать это — использовать length массива, возвращаемого Object.keys().
Итерация Map является итерируемым объектом, поэтому его можно итерировать напрямую.

Object не реализует протокол итерации, и поэтому объекты не являются напрямую итерируемыми с помощью оператора JavaScript for...of (по умолчанию).

Примечание:

  • Объект может реализовать протокол итерации, или вы можете получить итерируемый объект для объекта, используя Object.keys или Object.entries.
  • Оператор for...in позволяет итерировать перечисляемые свойства объекта.
Производительность

Работает лучше в сценариях, связанных с частым добавлением и удалением пар ключ-значение.

Не оптимизирован для частого добавления и удаления пар ключ-значение.

Сериализация и разбор

Нет встроенной поддержки сериализации или разбора.

(Но вы можете создать свою собственную поддержку сериализации и разбора для Map, используя JSON.stringify() с его аргументом replacer, а также используя JSON.parse() с его аргументом reviver. См. вопрос на Stack Overflow How do you JSON.stringify an ES6 Map?).

Встроенная поддержка сериализации из Object в JSON с использованием JSON.stringify().

Встроенная поддержка разбора из JSON в Object с использованием JSON.parse().

Установка свойств объекта

Установка свойств объекта также работает для объектов Map и может вызвать значительное замешательство.

Таким образом, кажется, что это работает:

const wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";

console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }

Но такой способ установки свойства не взаимодействует со структурой данных Map. Он использует возможности обычного объекта. Значение 'bla' не сохраняется в Map для запросов. Другие операции с данными завершаются неудачей:

wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }

Правильное использование для хранения данных в Map — это метод set(key, value).

const contacts = new Map();
contacts.set("Jessie", { phone: "213-555-1234", address: "123 N 1st Ave" });
contacts.has("Jessie"); // true
contacts.get("Hilary"); // undefined
contacts.set("Hilary", { phone: "617-555-4321", address: "321 S 2nd St" });
contacts.get("Jessie"); // {phone: "213-555-1234", address: "123 N 1st Ave"}
contacts.delete("Raymond"); // false
contacts.delete("Jessie"); // true
console.log(contacts.size); // 1

Браузерные API, похожие на Map

Браузерные объекты, похожие на Map (или «maplike-объекты»), — это интерфейсы Web API, которые во многом ведут себя как Map.

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

Разрешённые типы устанавливаются в определении IDL спецификации. Например, RTCStatsReport — это объект, похожий на Map, который должен использовать строки для ключей и объекты для значений. Это определено в IDL спецификации ниже:

interface RTCStatsReport {
  readonly maplike<DOMString, object>;
};

Объекты, похожие на Map, бывают либо доступными только для чтения (read-only), либо доступными для чтения и записи (read-writable) (см. ключевое слово readonly в IDL выше).

  • Объекты, похожие на Map, доступные только для чтения, имеют свойство size и методы: entries(), forEach(), get(), has(), keys(), values(), и [Symbol.iterator]().
  • Объекты, похожие на Map, доступные для записи, дополнительно имеют методы: clear(), delete(), и set().

Методы и свойства имеют то же поведение, что и эквивалентные сущности в Map, за исключением ограничения на типы ключей и значений.

Ниже приведены примеры браузерных объектов, похожих на Map, доступных только для чтения:

  • AudioParamMap
  • CSSFontFeatureValuesMap
  • EventCounts
  • KeyboardLayoutMap
  • MIDIInputMap
  • MIDIOutputMap
  • RTCStatsReport

Конструктор

Map()
Создает новый объект Map.

Статические свойства

Map[Symbol.species]
Функция-конструктор, используемая для создания производных объектов.

Статические методы

Map.groupBy()
Группирует элементы заданного итерируемого объекта, используя значения, возвращаемые предоставленной функцией обратного вызова. Конечный возвращаемый Map использует уникальные значения из тестовой функции в качестве ключей, которые могут быть использованы для получения массива элементов в каждой группе.

Свойства экземпляра

Эти свойства определены в Map.prototype и используются всеми экземплярами Map.

Map.prototype.constructor
Функция-конструктор, которая создала объект экземпляра. Для экземпляров Map начальным значением является конструктор Map.
Map.prototype.size
Возвращает количество пар ключ/значение в объекте Map.
Map.prototype[Symbol.toStringTag]
Начальным значением свойства [Symbol.toStringTag] является строка "Map". Это свойство используется в Object.prototype.toString().

Методы экземпляра

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

Примеры

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

const myMap = new Map();

const keyString = "a string";
const keyObj = {};
const keyFunc = () => {};

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

console.log(myMap.size); // 3

// getting the values
console.log(myMap.get(keyString)); // "value associated with 'a string'"
console.log(myMap.get(keyObj)); // "value associated with keyObj"
console.log(myMap.get(keyFunc)); // "value associated with keyFunc"

console.log(myMap.get("a string")); // "value associated with 'a string'", because keyString === 'a string'
console.log(myMap.get({})); // undefined, because keyObj !== {}
console.log(myMap.get(() => {})); // undefined, because keyFunc !== () => {}

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

NaN также может использоваться в качестве ключа. Несмотря на то, что каждый NaN не равен самому себе (NaN !== NaN истинно), следующий пример работает, потому что 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 (const [key, value] of myMap) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

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

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

for (const [key, value] of myMap.entries()) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

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

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

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

Связь с объектами Array

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

// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray);

console.log(myMap.get("key1")); // "value1"

// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)); // Will show you exactly the same Array as kvArray

// A succinct way to do the same, using the spread syntax
console.log([...myMap]);

// Or use the keys() or values() iterators, and convert them to an array
console.log(Array.from(myMap.keys())); // ["key1", "key2"]

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

Подобно Array, Map могут быть клонированы:

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

const clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false (useful for shallow comparison)

Примечание: Имейте в виду, что сами данные не клонируются. Другими словами, это только поверхностная копия Map.

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

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

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

// Merge two maps. The last repeated key wins.
// Spread syntax essentially converts a Map to an Array
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"],
]);

// Merge maps with an array. The last repeated key wins.
const merged = new Map([...first, ...second, [1, "un"]]);

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

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

Спецификация
ECMAScript® 2027 Language Specification
# sec-map-objects

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

Десктопные Мобильные Серверные
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
Map
38
12
13
25
8
38
14
25
8
3.0
38
8
1.0.0
1.0
0.12.0
@@iterator
38
12
36
27–36Используется свойство-заполнитель с именем @@iterator.
17–27Используется свойство-заполнитель с именем iterator.
25
10
38
36
27–36Используется свойство-заполнитель с именем @@iterator.
17–27Используется свойство-заполнитель с именем iterator.
25
10
3.0
38
10
1.0.0
1.0
0.12.0
@@species
51
13
41
38
10
51
41
41
10
5.0
51
10
1.0.0
1.0
6.5.0
Map
38
12
13
25
8
38
14
25
8
3.0
38
8
1.0.0
1.0
0.12.0
clear
38
12
19
25
8
38
19
25
8
3.0
38
8
1.0.0
1.0
0.12.0
delete
38
12
13
25
8
38
14
25
8
3.0
38
8
1.0.0
1.0
0.12.0
entries
38
12
20
25
8
38
20
25
8
3.0
38
8
1.0.0
1.0
0.12.0
forEach
38
12
25
25
8
38
25
25
8
3.0
38
8
1.0.0
1.0
0.12.0
get
38
12
13
25
8
38
14
25
8
3.0
38
8
1.0.0
1.0
0.12.0
getOrInsert
145
145
144
129
26.2
145
144
96
26.2
Нет
145
26.2
1.2.20
2.6.7
26.0.0
getOrInsertComputed
145
145
144
129
26.2
145
144
96
26.2
Нет
145
26.2
1.2.20
2.6.7
26.0.0
groupBy
117
117
119
103
17.4
16.4–17.4
117
119
78
17.4
16.4–17.4
24.0
117
17.4
16.4–17.4
1.0.19
1.37
21.0.0
has
38
12
13
25
8
38
14
25
8
3.0
38
8
1.0.0
1.0
0.12.0
key_equality_for_zeros
38
12
29
25
9
38
29
25
9
3.0
38
9
1.0.0
1.0
4.0.0
keys
38
12
20
25
8
38
20
25
8
3.0
38
8
1.0.0
1.0
0.12.0
set
38
12
13
25
8
38
14
25
8
3.0
38
8
1.0.0
1.0
0.12.0
size
38
12
19Начиная с Firefox 13 по Firefox 18 свойство size было реализовано как метод Map.prototype.size(), что было изменено на свойство в более поздних версиях для соответствия спецификации ECMAScript 2015.
25
8
38
19Начиная с Firefox for Android 14 по Firefox for Android 18 свойство size было реализовано как метод Map.prototype.size(), что было изменено на свойство в более поздних версиях для соответствия спецификации ECMAScript 2015.
25
8
3.0
38
8
1.0.0
1.0
0.12.0
values
38
12
20
25
8
38
20
25
8
3.0
38
8
1.0.0
1.0
0.12.0

См. также

  • Полифил для Map в core-js
  • Полифил es-shims для Map
  • Set
  • WeakMap
  • WeakSet

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API