# 01. Map

`Map` — коллекция для хранения записей вида `ключ:значение`. Предпочтительнее использовать вместо объектов, когда нужна структура вида ключ-значение.

Отличия карт от объектов:

* В объектах в которых ключами могут быть только строки, в `Map` ключом может быть произвольное значение, в том числе объект или функция.
* Объект имеет прототипы, что влияет на его ключи. Карты с этой точки зрения выступают как "чистые объекты".
* Можно легко получить размер карты, размер объектов много сложнее.
* Карта сохраняет пары ключ-значение в порядке их добавления.
* Перебор гарантированно осуществляется в порядке вставки.
* На картах реализованы символы
  * `Symbol.iterator`
  * `Symbol.toStringTag`
  * `Symbol.species`

## Create Map

При создании `Map` можно сразу инициализировать списком значений. Аргументом new `Map` должен быть итерируемый объект (не обязательно именно массив):

```javascript
// Create new empty map.
const map = new Map();

// From array of pairs or from any iterable of pairs
const map = new Map([
  [1, "one"],
  [2, "two"],
  [3, "three"] // trailing comma is ignored
]);

const map2 = new Map()
  .set(1, "one")
  .set(2, "two")
  .set(3, "three");
```

`Object.entries()` also lets you set up a Map via an object. This is more concise than using an Array of 2-element Arrays, but keys can only be strings:

```javascript
let map = new Map(
  Object.entries({
    one: 1,
    two: 2
  })
);
```

## `Map` API

[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)

Для сохранения и чтения значений используются методы `get` и `set`. И ключи и значения сохраняются «как есть», без преобразований типов.

Другие методы:

* `size` - число записей в `Map`.
* `clear()` - удаляет все записи из карты.
* `delete()` - удаляет запись с ключом `key`, возвращает `true`, если такая запись была, иначе `false`.
* `has()` - возвращает `true`, если ключ есть, иначе `false`.
* `get()` - возвращает значение по ключу или `undefined`
* `set()` - ассоциирует значение с ключом и возвращает текущую карту.

```javascript
let map = new Map();

map.set(1, "Anton").set("2", "Nastya");

map.size; //  2
map.get(1); // Anton
map.get("2"); // Nastya
map.get(2); // undefined
```

Для проверки значений на эквивалентность используется алгоритм `SameValueZero`. Он аналогичен строгому равенству `===`, отличие — в том, что `NaN` считается равным `NaN`. Поэтому значение `NaN` также может быть использовано в качестве ключа.

## `Map` iteration

Для итерации по `map` используется один из трёх методов:

* `map.keys()` — возвращает итерируемый объект для ключей,
* `map.values()` — возвращает итерируемый объект для значений,
* `map.entries()` — возвращает итерируемый объект для записей `[ключ, значение]`, он используется по умолчанию в `for..of`.
* `for..of` - аналогичен вызову `map.entries()`
* `[...map]` - аналогичен вызову метода `map.entries()`.
* Карты имеют метод `forEach`, но не имеют методов `map` и `filter`.

```javascript
const map = new Map().set(false, "no").set(true, "yes");

for (const [key, value] of map.entries()) {
  console.log(key, value);
}
```

Notice that `map.values()` and `map.entries()` return iterator objects. To put the result into an array, the spread operator `...` is necessary. In a `for..of` loop statement the iterator can be used directly.

```javascript
const map = new Map().set(false, 'no').set(true, 'yes');
[...map.keys()]     // [ false, true ]
[...map.values()]   // ['no', 'yes']
[...map.entries()]  // [[false, 'no'], [true, 'yes']]
```

Карты можно комбинировать используя `spread` операторы в конструкторе:

```javascript
const combinedMap = new Map([...map1, ...map2])
[...combinedMap] // convert to Array to display
[ [ 1, 'a1' ],
  [ 2, 'b2' ],
  [ 3, 'c2' ],
  [ 4, 'd2' ] ]
```

К карты не имеют функции `map`, но её можно соответствующим образом эмулировать:

```javascript
let map0 = new Map([
  [1, "a"],
  [2, "b"],
  [3, "c"]
]);

let map1 = new Map( // step 3
  [...map0] // step 1
    .map(([k, v]) => [k * 2, "_" + v]) // step 2
);
// Resulting Map: {2 -> '_a', 4 -> '_b', 6 -> '_c'}
```

Аналогичным образом можно эмулировать функцию `filter`.

## Conversions

Конверсия карты в JSON и обратно:

```javascript
function mapToJson(map) {
  return JSON.stringify([...map]);
}
function jsonToMap(jsonStr) {
  return new Map(JSON.parse(jsonStr));
}
```

Конверсия карт в объекты возможна только если все ключи карты являются строками:

```javascript
function mapToObj(map) {
  const obj = Object.create(null);
  for (const [k, v] of map) {
    // We don’t escape the key '__proto__'
    // which can cause problems on older engines
    obj[k] = v;
  }
  return obj;
}

function objToMap(obj) {
  const map = new Map();
  for (const k of Object.keys(obj)) {
    map.set(k, obj[k]);
  }
  return map;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://strctr.gitbook.io/programming/01-languages/javascript/01-language/b-structured/b5-collections/01-maps.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
