`Map` объект
В этой статье объясняется объект Map.
Мы пошагово объясним, начиная с базовых операций и заканчивая практическими примерами, полезными для реальных задач.
YouTube Video
Map объект
Map — это коллекция, которая хранит пары ключ-значение. Это похоже на объект, но отличается тем, что в качестве ключей могут использоваться любые типы, такие как объекты, функции или примитивы, и сохраняется порядок вставки.
Основы Map
Сначала давайте посмотрим, как создать Map и выполнять базовые операции.
Следующий код является минимальным примером, который создаёт пустую карту, добавляет ключи и получает значения.
1// Create an empty Map and add key-value pairs
2const m = new Map();
3m.set('a', 1);
4m.set('b', 2);
5
6console.log(m.get('a')); // 1
7console.log(m.size); // 2
- В этом коде вы можете добавлять элементы с помощью
set, получать значения с помощьюgetи проверять количество элементов с помощьюsize. Mapсохраняет порядок вставки, что делает его удобным для обработки, зависящей от порядка.
Поведение методов set, get, has и delete
Ниже приведены примеры типичных операций чтения, записи, проверки наличия и удаления.
С этим кодом вы можете проверить возвращаемые значения и эффекты каждого метода.
1// Demonstrate set, get, has, and delete
2const m2 = new Map();
3m2.set('x', 10);
4console.log(m2.has('x')); // true
5console.log(m2.get('y')); // undefined
6
7m2.delete('x');
8console.log(m2.has('x')); // false
9
10// set returns the map itself, allowing method chaining
11m2.set('a', 1).set('b', 2);
12console.log(m2); // Map { 'a' => 1, 'b' => 2 }
getвозвращаетundefined, если ключ не существует.hasпроверяет наличие ключа, аdeleteудаляет ключ.- Кроме того, так как
setвозвращает сам объект map, возможна цепочка вызовов методов.
В качестве ключа может использоваться любой тип (использование объектов в качестве ключей)
Одним из основных преимуществ Map является то, что вы можете использовать объекты напрямую в качестве ключей.
В следующем примере показано, как ассоциировать значения в Map, используя объекты в качестве ключей.
1// Use objects as keys in a Map
2const keyObj = { id: 1 };
3const keyFunc = () => {};
4const objMap = new Map();
5
6// Another object with the same content but a different reference
7const anotherKeyObj = { id: 1 };
8
9objMap.set(keyObj, 'objectValue');
10objMap.set(keyFunc, 'functionValue');
11objMap.set(anotherKeyObj, 'anotherValue');
12
13console.log(objMap.get(keyObj)); // 'objectValue'
14console.log(objMap.get(keyFunc)); // 'functionValue'
15console.log(objMap.get(anotherKeyObj)); // 'anotherValue'
- При использовании объектов в качестве ключей важно, чтобы это были одни и те же ссылки. Даже если их содержимое одинаково, объекты с разными ссылками считаются разными ключами.
Итерация (перебор)
Map сохраняет порядок вставки, поэтому часто используется перебор.
Ниже мы покажем, как использовать for...of, forEach, а также методы keys(), values() и entries().
1// Iterating a Map with for...of and forEach
2const iterMap = new Map([['a', 1], ['b', 2], ['c', 3]]);
3
4// for...of over entries (default)
5for (const [key, value] of iterMap) {
6 console.log(key, value);
7}
8
9// forEach callback
10iterMap.forEach((value, key) => {
11 console.log(key, value);
12});
13
14// keys() and values()
15console.log([...iterMap.keys()]); // ['a','b','c']
16console.log([...iterMap.values()]); // [1,2,3]
entries()возвращает массив пар[ключ, значение], который можно превратить в массив с помощью оператора расширения. Обратите внимание, что функция обратного вызова дляforEachполучает аргументы в порядкеvalue, key.
Преобразование между Map и Object
Вы можете преобразовать существующий объект в Map или Map в обычный объект или массив.
1// Convert between Map and Object / Array
2const obj = { a: 1, b: 2 };
3const mapFromObj = new Map(Object.entries(obj)); // Object -> Map
4console.log(mapFromObj.get('a')); // 1
5
6const objFromMap = Object.fromEntries(mapFromObj); // Map -> Object
7console.log(objFromMap); // { a: 1, b: 2 }
8
9const arrayFromMap = [...mapFromObj]; // Map -> Array of [key, value]
10console.log(arrayFromMap); // [['a',1], ['b',2]]
- Использование
Object.entriesиObject.fromEntriesупрощает преобразование. Однако, поскольку ключи объекта ограничены строками или символами, при обратном преобразовании в объект нестроковые ключи теряются.
Практический пример: подсчет частоты (Count Map)
При подсчёте частоты элементов в массиве использование Map упрощает этот процесс.
Следующий код является примером использования Map для подсчета частоты строк в массиве и их сортировки.
1// Count frequencies with Map
2const arr = ['apple','banana','apple','orange','banana','apple'];
3const freq = new Map();
4
5for (const item of arr) {
6 freq.set(item, (freq.get(item) || 0) + 1);
7}
8
9console.log([...freq.entries()]); // [['apple',3], ['banana',2], ['orange',1]]
- Использование
Mapпозволяет легко проверять наличие и обновлять элементы. Это можно сделать и с объектами, ноMapможет быть более интуитивен при работе с произвольными ключами.
Замечания по поводу Map и JSON.stringify (Сериализация)
JSON.stringify не может напрямую сериализовать объект Map. Если вам нужно сохранить Map, сначала необходимо его преобразовать.
Следующий пример показывает, как преобразовать Map в массив, прежде чем сериализовать его в JSON, и как его восстановить.
1// Serialize and deserialize a Map
2const m3 = new Map([['x', 1], ['y', 2]]);
3const json = JSON.stringify([...m3]); // convert to array first
4console.log(json); // '[["x",1],["y",2]]'
5
6const restored = new Map(JSON.parse(json));
7console.log(restored.get('x')); // 1
- Карты, которые необходимо сохранить или передать, следует перед сериализацией преобразовывать в массивы. При восстановлении используйте
JSON.parseдля преобразования в массив, затем превратите его обратно в Map.
Введение в WeakMap и как его использовать
WeakMap отличается тем, что его ключи имеют слабые ссылки (подвержены сборке мусора).
Он полезен для хранения кэша или метаданных с объектами в качестве ключей, автоматически освобождая их, когда объект-ключ собирается сборщиком мусора.
1// WeakMap for metadata tied to object lifecycle
2const wm = new WeakMap();
3let obj = {};
4wm.set(obj, { meta: 'info' });
5console.log(wm.get(obj)); // { meta: 'info' }
6
7obj = null; // now the object can be GC'd and its entry removed from WeakMap
WeakMapнельзя перебирать или проверить его размер, но он полезен для предотвращения утечек памяти.
Резюме
Map — это удобная коллекция, которая, в отличие от объектов, допускает любой тип в качестве ключа и сохраняет порядок вставки. Поняв всё — от базовых операций до продвинутого использования, вы сможете более гибко и интуитивно управлять данными. Используя Object и Map соответствующим образом в зависимости от ситуации, вы сможете значительно повысить ясность и читаемость кода.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.