hellojs.ru
Главная - Дополнительные основы JavaScript - Map

Map

Размещено в категории "Дополнительные основы JavaScript"
28.10.2024 / просмотров: 39 / комментариев: 0
Ресурсы:

Документация
Первая половина статьи
Страница учебника




Map ('мэпы') - коллекции, или карты.

В объектах зачастую в качестве свойств используются строки:

Код

const obj = {
  name: 'Alex',
  age: 22
}

В данном случае, к примеру, свойство name является строкой, хоть и записано без кавычек, это всё равно строка.

Что же будет, если в качестве ключа передать не строку, а к примеру число:

Код

const obj = {
  4: 'Alex',
  age: 22
}


А произойдёт то, что 4 превратится в строку и в этом можно убедиться, если вывести в консоль самый первый ключ нашего объекта

Код

console.log(typeof(Object.keys(obj)[0])); // string

Но если в качестве ключа мы попробуем поставить объект, то получим ошибку.

Но бывают ситуации, когда вместо строк в качестве ключей нам нужны другие типы данных.

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

Код

const shops = [
  {rice: 500},
  {oil: 200},
  {bread: 50}
]

К каждому из этих объектов (один объект - это один магазин) нужно добавить его бюджет, таким образом, чтобы сформировались пары магазин - бюджет.

Чтобы создать новую карту:

Код

const map = new Map();

Созданная новая карта изначально пустая и её нужно заполнить.

В качестве ключей в "мэпах" можно использовать массивы, объекты, функции и т.д.
По типу данных "мэпы" - это всё те же объекты, но со своими специфическими методами.

Метод set()



Синтаксис этого метода:

Код

map.set(ключ, значение);

Применительно к нашим магазинам:

Код

map.set(shops[0], 5000);
map.set(shops[1], 15000);
map.set(shops[2], 25000);

Или тоже самое, но цепочкой:

Код

map.set(shops[0], 5000).set(shops[1], 15000).set(shops[2], 25000);

Или, как вариант, для удобства читаемости:

Код

map.set(shops[0], 5000)
  .set(shops[1], 15000)
  .set(shops[2], 25000);

Работа цепочки возможна благодаря тому, что каждый раз, когда отрабатывает звено цепочки, обратно возвращается объект map

Если сейчас вывести в консоль содержимое нашей карты:

Код

console.log(map);

То увидим:

Цитата

Map(3) {
{ rice: 500 } => 5000,
{ oil: 200 } => 15000,
{ bread: 50 } => 25000
}

Мы видим что это объект, у которого свойства (ключи) также являются объектами

Цифры бюджетов магазинов могут приходить из каких-то таблиц, либо баз данных

Код

const budget = [5000, 15000, 25000];

И тогда нам нужно соединить две структуры: массив с магазинами и массив с бюджетами, для этого мы можем использовать обычный цикл, либо метод forEach():

Код

shops.forEach((shop, i) => {
  map.set(shop, budget[i]);
})

В аргумент shop при переборе по очереди будут попадать каждый из трёх объектов, содержащихся в массиве shops, при этом i - это порядковый номер каждого из элементов массива.

Если сейчас вывести в консоль содержимое карты, то получим тот же результат, что и до этого.

Работа с картами



Код

map.get(shops[0]); // 5000

map.get(key) - возвращает значение по ключу или undefined, когда ключ key отсутствует

Проверка на наличие какого-то ключа в карте:

Код

map.has(shops[0]); // true

map.has(key) - вернёт true, если ключ key в коллекции есть, иначе false

Удалить пару "ключ-значение":

Код

map.delete(key);

Полностью очистить карту от всех элементов:

Код

map.clear();

Узнать текущее количество элементов карты:

Код

map.size; // это свойство

В консоли карта выглядит как объект с объектами, но на самом деле это массив массивов!

Убедимся в этом, добавив в качестве аргумента первое начальное значение для магазинов. Это будет начальное значение при создании карты, затем добавятся остальные с помощью forEach()

Код

const map = new Map([
  [{paper: 400}, 8000]
]);

в консоли получаем ожидаемый результат

Цитата

Map(4) {
{ paper: 400 } => 8000,
{ rice: 500 } => 5000,
{ oil: 200 } => 15000,
{ bread: 50 } => 25000
}


Методы перебора карты



map.keys() - возвращает итерируемый объект по ключам, пример:

Код

for (let shop of map.keys()) {
  console.log(shop);
}

Результат в консоли:

Цитата

{paper: 400}
{rice: 500}
{oil: 200}
{bread: 50}

Пример №2 : можно получить список товаров всех магазинов.

Создадим для начала переменную с пустым массивом:

Код

let goods = [];

Чтобы записать в этот массив все товары, мы можем сделать так:

Код

for (let shop of map.keys()) {
  goods.push(Object.keys(shop)[0]);
}

console.log(goods);

Результат в консоли:

Цитата

[ 'paper', 'rice', 'oil', 'bread' ]

Почему именно такая запись?

Код

Object.keys(shop)[0];

Потому, что если записать так

Код

Object.keys(shop);

то в консоли будет массив с массивами

Код

[ ['paper'], ['rice'], ['oil'], ['bread'] ]

поэтому, чтобы из каждого массива вытащить его элемент, мы и добавляем его индекс [0]

Всё дело в том, что Object.keys() возвращает массив из перечисляемых свойств объекта, соответственно:

Код

Object.keys({paper: 400})

вернёт

Код

['paper']

По аналогии:

Код

Object.keys({rice: 500})

вернёт

Код

['rice']

И так далее.

Нам же нужен один массив со списком товаров, поэтому из каждого возвращенного с помощью Object.keys() массива мы вынимаем его элемент с помощью его индекса [0].

Второй способ позволяет получить вместо ключей значения:

Код

for (let price of map.values()) {
  console.log(price);
}

В консоли мы получим бюджеты каждого из магазинов:

Цитата

8000
5000
15000
25000

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

Код

for (let price of map.entries()) {
  console.log(price);
}

Результат в консоли:

Цитата

[ { paper: 400 }, 8000 ]
[ { rice: 500 }, 5000 ]
[ { oil: 200 }, 15000 ]
[ { bread: 50 }, 25000 ]

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

Код

for (let [shop, price] of map.entries()) {
  console.log(price, shop);
}

И вот результат:

Цитата

8000 { paper: 400 }
5000 { rice: 500 }
15000 { oil: 200 }
25000 { bread: 50 }

Четвёртый способ перебрать карту - это иcпользовать метод forEach()

Код

map.forEach((value, key, map) => {
  console.log(key, value);
});

И результат:

Цитата

{ paper: 400 } 8000
{ rice: 500 } 5000
{ oil: 200 } 15000
{ bread: 50 } 25000


Как сделать карту из объекта



Мы можем использовать Object.entries() для создания карты из имеющегося объекта:

Код

const user = {
  name: 'Alex',
  surname: 'Smith',
  birthday: '20/04/1993',
  showMyPublicData: function() {
  console.log(`${this.name} ${this.surname}`);
  }
}

const userMap = new Map(Object.entries(user));

console.log(userMap);

И в консоли мы получим карту, созданную из объекта

Цитата

Map(4) {
'name' => 'Alex',
'surname' => 'Smith',
'birthday' => '20/04/1993',
'showMyPublicData' => [Function: showMyPublicData]
}


Как создать из карты объект



Метод Object.fromEntries() преобразует список пар "ключ-значение" в объект

Код

const newUserObj = Object.fromEntries(userMap);

Еще пример:

Код

const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42]
]);

const obj = Object.fromEntries(entries);
console.log(obj);

Цитата

{ foo: 'bar', baz: 42 }


Главные отличия карт от объектов



1. У карт ключи могут быть чем угодно: массивами, объектами, функциями, цифрами и т.п. У объектов ключами могут быть только строки

2. Порядок свойств в картах всегда такой, какой мы его добавляли. У объектов нет четкого порядка относительно того, когда было добавлено свойство. Например, если свойство в объект добавляется динамически, оно может быть подставлено в любое место объекта.

3. При создании пустой карты в ней ничего не будет содержаться, в том числе каких-то наследуемых свойств через прототип, а в пустом объекте они есть.

4. Карты легко перебирать и для этого есть много способов.

5. Размеры карты легко получить через свойство size, с объектом же требуется сначала его трансформация в массив, чтобы затем получить его длину.
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
Сайт управляется системой uCoz