В стандарте EcmaScript 2015, больше известном, как ES6, появился объект Map (карта), который позволяет сохранить данные в виде коллекции из пар ключ/значение, примерно такой же как и Object. Однако Map позволяет использовать ключи любого типа, а не только в виде строк. В каком-то смысле она похожа и на двумерный массив, и на объект, но с более сложной организацией.Для того чтобы создать коллекцию Map, нельзя использовать литерал, необходимо создать экземпляр класса Map. Например:

Для того чтобы заполнить коллекцию, можно использовать метод myMap.set(key, value) , то есть записать в ключ key значение value. Например:

Можно передать в Map данные в виде пар [key, value] сразу при создании экземпляра. Интересно, что в виде ключей в Map могут выступать и объекты, и массивы, и даже функции, что невозможно для обычных объектов, создаваемых как литералы вида let person = { name: "Mary", age: 23 } или let lisa = new Object( {name: "Lisa", age: 15 } ). В этом случае запись данных в коллекцию Map может быть такой:

Получить информацию о содержимом коллекции Map или удалить/очистить информацию в ней можно с помощью таких методов:

  • map.get(key) – возвращает значение по указанному в скобках ключу. Если ключ key отсутствует, вернет undefined .
  • map.has(key) – возвращает true, если ключ key присутствует в коллекции, если его нет - false.
  • map.delete(key) – удаляет элемент по переданному ключу key.
  • map.clear() – очищает коллекцию от всех элементов.
  • map.size – возвращает текущее количество элементов. Обратите внимание, что это свойство, а не метод. Круглые скобки не нужны.

Например, если мы захотим проверить, какое значение лежит в коллекции objMap из кода выше по ключу numArr, то нужно будет записать:

Если нужно проверить наличие определенного ключа, то нам поможет метод objMap.has(person).

Пример использования методов работы с коллекцией Map

Давайте попробуем создать несколько html-элементов с помощью коллекции Map и изображений с сайта unsplash.com, которые выведем в тело документа с помощью document.write(). На сайте unsplash.com подберем изображения фруктов, а затем добавим их в коллекцию fruitsMap. Переберем эту коллекцию с помощью встроенного метода forEach() для Map и при добавлении разметки  запишем обработчик события onclick как атрибут тега <figure>.

Обратите внимание, что при удалении элемента из fruitsMap ключ помещен в кавычки, т.к. в коллекции он имеет строковый тип данных.

Попробуйте сами подсчитать количество элементов в fruitsMap в самом начале и при удалении картинок по щелчку левой кнопкой мыши.

Практическое использование коллекции Map для перевода слов

Рассмотрим еще один пример, который может пригодиться в практике преподавателей иностранных языков. Мы запишем в коллекцию Map 10 английских слов и их перевод, а затем выведем их для пользователя в виде перечня из слов, которые надо перевести, и полей ввода, куда нужно записать перевод. Причем сделаем подсказку пользователю в виде выпадающего списка, в котором будут представлены все варианты перевода.

Давайте посмотрим на работающий пример:

HTML-разметка примера:

Стили вы можете написать сами, но в скрипте предполагается наличие одного класса, содержащего css-свойство display: flex (.d-flex) и вложенных в него двух div-элементов с классом .my-col, содержащим правило flex: 0 0 50% для создания 2-х одинаковых по ширине столбцов с помощью модели Flexbox.

Код JavaScript

В JS-коде необходимо:

  1. Создать коллекцию Map с 10 английскими и русскими словами. Мы назовем ее wordsMap.
  2. Получить доступ к элементу <div class="task"></div>, который будет заполнен словами из wordsMap.
  3. Сформировать выпадающий список с подсказками в виде <datalist id="rusTranslate">, куда будут помещаться только русские слова, т.е. wordsMap.values().
  4. Преобразовать wordsMap в массив с помощью статического метода массивов Array.from() и отсортировать его по алфавиту, т.к. нам нельзя выдавать подсказки к английским словам в том же порядке, в каком они идут в wordsMap.
  5. Перебрать все ключи и значения коллекции wordsMap и вывести их в виде разметки в 2 столбца. При этом мы запишем правильное значение перевода в атрибут data-answer, чтобы потом сравнить его значение с тем value, которое пользователь введет в поле ввода.
  6. Получить доступ ко все сформированным на основе прохода по элементам wordsMap <div class="my-col russian">, чтобы обработать значения каждого из размещенного в них input-а при клике на кнопке с id="checkBtn".
  7. Сравнить при клике value поля ввода и значение атрибута data-answer. Если слово переведено верно, то ставим + возле английского слова, добавляя к заложенному при формировании строки разметки элементу <span> класс .plus. В случае неверного ответа - ставим - перед английским словом с помощью класса .minus.
  8. Определить количество правильных и неправильных ответов по количеству соответствующих классов .plus и .minus.
  9. Вывести результат в абзаце перед кнопкой с id="resultInfo" и заодно проверить окончания в слове "ответов", которое зависит от цифры перед ним: 1 ответ, 2 ответа, 5 ответов.

Как можно заметить из списка, при создании кода нужно учесть целый ряд моментов, хотя пример совсем не кажется сложным.

Вы можете найти комментарии всех действий в коде ниже. Помимо обработки значений коллекции Map, вам понадобится понимание того, как осуществляется выбор разных элементов на html-странице и обработка событий.

Методы Map.keys(), Map.values(), Map.entries()

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

В примере ниже мы используем объект Map для того, чтобы назначить стилевые свойства для обзаца, и методы keys() и values() - для того, чтобы вывести, какие данные мы использовали. Для перебора данных с помощью обоих методов мы будем использовать циклы for ... of, т.к. объекты типа Map являются итерируемыми, т.е. все их данные в виде пар "ключ" - "значение" имеют индексы.

See the Pen Map with styles by Elen (@ambassador) on CodePen.0

Следующий пример, наоборот, берет данные стилей из html-элемента и преобразует их в объект Map.
Здесь мы будем использовать метод Map.entries() для вывода этих данных.

Отличия объектов (Object) и коллекций Map

Работа с коллекциями Map временами напоминает работу с объектами. Подход может быть похожим, но между объектами и коллекциями Map есть ряд отличий:

  1. В объектах ключами могут быть только строки. В Map ключами могут быть строки, числа, объекты и даже функции.
  2. Коллекции Map являются итерируемыми, и могут перебираться в циклах for..of или методом forEach(). Перебрать таким образом свойства объекта не удасться, так как строковые значения не являются итерируемыми.
  3. В Map можно получить размер коллекции с помощью свойства size (аналогично length для массивов). В объектах мы не можем получить их размер, т.к. такого свойства у них нет. В объектах можно посчитать количество свойств, используя методы keys() или values().
  4. Объекты очень просто перевести в JSON-формат с помощью метода JSON.stringify() или, напротив, из JSON-формата перевести данные в объект методом JSON.parse(). Для коллекции Map так просто это сделать не получится.

В заключение

Для браузеров на основе Chrome коллекции Map могут содержать 16 миллионов записей, а объекты могут содержать только 11 миллионов. Так что использовать Map можно и для очень больших наборов данных.

Метки:

Автор: Админ

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *