Итак, мы с вами рассмотрели
примитивные типы, объекты и массивы. Для полноты картины не хватает еще двух
структур данных – это карты (Map) и наборы (Set). И на этом
занятии мы с ними познакомимся. Начнем с карт Map.
Map
Помните, когда
мы говорили об объектах, то отмечали, что ключи (имена свойств) являются
строками – всегда строки. Так вот, в отличие от объектов в Map в качестве
ключа могут выступать не только строки, но вообще любые типы данных.
У Map есть такие
методы и свойства:
-
new
Map() – создаёт коллекцию;
-
map.set(key,
value) – записывает по ключу key значение value;
-
map.get(key)
– возвращает значение по ключу или undefined, если ключ key отсутствует;
-
map.has(key)
– возвращает true, если ключ key присутствует в коллекции, иначе false;
-
map.delete(key)
– удаляет элемент по ключу key;
-
map.clear()
– очищает коллекцию от всех элементов;
-
map.size
– возвращает текущее количество элементов.
Рассмотрим их. Например:
let m = new Map();
m.set("string", "строка");
m.set(7, "простое число");
m.set(true, {descr: "boolean", value: true});
console.log( m.get("string") );
console.log( m.get(7) );
console.log( m.get(true) );
В качестве
ключей можно использовать и объекты, например:
let user = {
name: "JavaScript",
type: "ES6"
};
let m = new Map();
m.set(user, "объект user");
console.log( m.get(user) );
Часто коллекцию Map используют
благодаря этому свойству – возможности использования объектов в качестве
ключей. Ни одна другая структура в JavaScript не обладает
таким свойством.
Чтобы сравнивать
ключи, объект Map использует алгоритм SameValueZero. Это почти такое же
сравнение, что и ===, с той лишь разницей, что NaN считается равным NaN. Так
что NaN также может использоваться в качестве ключа. Причем этот встроенный алгоритм
сравнения не может быть заменён или модифицирован.
Создать объект Map также можно на
основе двумерного массива:
let car = new Map([
["model", "opel"],
["color", 0xff],
["price", 1000]
]);
Здесь каждый
элемент массива интерпретируется как «ключ – значение». В итоге коллекция car содержит три
элемента с ключами model, color, price и
соответствующими значениями.
Вообще, объект Map можно создать
на основе любого итерируемого объекта, представляющего данные в формате «ключ -
значение». Например, можно взять некий объект:
let book = {
author: "Пушкин",
title: "Онегин",
pages: 100,
price: 80
};
И создать из
него карту:
let lib = new Map(Object.entries(book));
Здесь метод
объекта entries преобразует
объект book в массив с
элементами «ключ – значение», на основе которого и формируется lib.
Есть также
противоположный метод Object.fromEntries, который из двумерного массива по формату
«ключ-значение», формирует объект:
let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['meat', 4]
]);
В частности,
этот принцип используется для преобразования Map в Object:
let objLib = Object.fromEntries(lib.entries());
console.log(objLib);
Здесь метод entries коллекции Map, также как и у Object, преобразует
содержимое в двумерный массив по формату «ключ-значение». Затем, с помощью
метода fromEntries этот двумерный
массив преобразуется в объект. Вот так можно Map превратить в Object.
Но, вернемся к
коллекции car, переберем его
содержимое. Для этого, обычно, используется цикл for of следующим
образом:
for (let value of car) {
console.log(value);
}
В результате value принимает вид
массива [ключ, значение] и выводится в консоль.
Если нам нужно
выбрать только ключи из коллекции car, то можно сделать так:
for (let key of car.keys()) {
console.log(key);
}
Здесь мы в цикл передаем
итерируемый (перебираемый) объект по ключам и в цикле выводим ключи в консоль.
Для отображения
значений соответствующих ключей, передается другой итерируемый объект:
for (let value of car.values()) {
console.log(value);
}
В отличие от
обычных объектов Object, в Map перебор
происходит в том же порядке, в каком происходило добавление элементов.
Еще одним
вариантом перебора служит цикл forEach, встроенный в объект Map:
Map.forEach( function(value, key, map) {
// что-то делаем
});
Например, можно
вывести в консоль информацию объекта Map следующим образом:
car.forEach((value, key) => {
console.log( `car[${key}] = ${value}` );
});
Здесь
используется стрелочная функция с двумя входными аргументами value и key.
Set
Коллекция Set формируется из
уникальных данных (без ключей – только данные). Уникальность означает, что одно
и то же значение не может быть добавлено дважды – оно просто проигнорируется.
Данный объект
имеет следующие методы и свойства:
-
new
Set(iterable) – создаёт Set, если в качестве аргумента был предоставлен
итерируемый объект (обычно это массив), то копирует его значения в Set;
-
set.add(value)
– добавляет значение (если оно уже есть, то ничего не происходит), возвращает
тот же объект set;
-
set.delete(value)
– удаляет значение, возвращает true если value было найдено и удалено, иначе
false;
-
set.has(value)
– возвращает true, если значение присутствует в коллекции, иначе false;
-
set.clear()
– удаляет все значения из набора;
-
set.size
– возвращает количество элементов в наборе.
Например, мы
ожидаем посетителей, и нам необходимо составить их список. Но повторные визиты
не должны приводить к дубликатам. Каждый посетитель должен появиться в списке
только один раз. Здесь как раз и подойдет множество Set:
let guests = new Set();
let alex = { name: "Alexey", old: 25 };
let oleg = { name: "Oleg", old: 32 };
let masha = { name: "Masha", old: 18 };
guests.add(alex);
guests.add(oleg);
guests.add(masha);
guests.add(alex);
guests.add(masha);
Выведем в
консоль получившийся набор:
for (let guest of guests) {
console.log(guest.name);
}
Получим только
троих гостей. Все так, как и должно быть.
Перебрать объект
Set также можно и с
помощью встроенного метода forEach. Он имеет следующий синтаксис:
Set.forEach(
function(value, valueAgain, set) {
// что-то делаем
});
Здесь второй
аргумент valueAgain добавлен для
синтаксической совместимости данного метода с аналогичным методом из Map. Это бывает
полезно, если программист решит вместо Set использовать Map. Тогда ему
достаточно будет поменять Set на Map и все
заработает уже с новым объектом.
Выполним перебор
элементов с помощью forEach:
guests.forEach( (item) => {
console.log(item.name+": "+item.old);
});
Как видите, все
достаточно просто. Перебор Map и
Set всегда осуществляется в порядке добавления элементов, так что нельзя
сказать, что это – неупорядоченные коллекции, но поменять порядок элементов или
получить элемент напрямую по его номеру здесь не получится.