В прошлом JavaScript был ограничен, когда речь шла о коллекциях. В то время как другие языки предлагают списки, наборы, ассоциативные карты и словари, JavaScript предлагает только массивы. Программисты JavaScript должны были придумать обходной путь для создания наборов или карт, что усложняло поддержку кода.
Теперь, с ES6, JavaScript предлагает новые встроенные классы для наборов и карт, которые значительно упрощают поддержку программирования. В этом руководстве мы подробно познакомим вас с сопоставлением и установкой вместе с примерами кода, вариантами использования и практическими упражнениями. Это руководство идеально подходит для разработчиков JavaScript, которые хотят улучшить свои навыки работы с JavaScript.
Краткий обзор этого руководства:
- Что такое
map
? - Как использовать
map
- Что такое
set
? - Как использовать
set
- Практическое упражнение с
map
- Что изучать дальше
Что такое map
?
До ES6 разработчики JavaScript использовали объекты для сопоставления ключей со значениями. Однако использование объекта в качестве карты имеет свои ограничения. Например:
- Не существует надежного способа перебора ключей, а метод
keys()
преобразует поля в строки, что приводит к конфликту ключей. - Нет простого способа добавить новые ключи и значения
В ES6 появилось несколько новых встроенных классов, в том числе тип коллекции с именем Map
, который может содержать пары ключ-значение любого типа. В отличие от объектного подхода, новый объект Map может запоминать порядок вставки ключей.
Проще говоря, JavaScript Map
представляет собой ассоциативный набор различных ключей и значений. И ключи, и значения могут быть любым примитивом или объектом. Это важная структура данных с множеством полезных применений.
Примечание.
WeakMap
похоже на карту, но все ключиWeakMap
являются объектами.
Чтобы создать новый Map
, мы используем следующий синтаксис:
let map = new Map([iterable]);
Давайте применим это на практике на более сложном примере. Ниже у нас есть карта, которая содержит имена в качестве ключей и оценки в качестве значений.
'use strict';
//START:DEFINE const scores = new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);
scores.set('Jake', 14);
console.log(scores.size); //END:DEFINE
--> 5
- Карта
scores
была инициализирована именами и очками. Исходными данными может быть любой итерируемый объект с парой ключей и значений. - Мы добавляем ключ и значение в Map, используя метод
set()
(строка 7) - Чтобы выяснить, сколько ключей в настоящее время находится на карте, мы используем свойство size (строка 9).
Примечание.
Map.has(key)
выше вернет логическое значение, указывающее, находится ли элемент, связанный с указанным ключом, на карте.
Как пользоваться картой
Как только мы узнаем, как создавать карты с помощью JavaScript, мы можем многое с ними делать.
Итерация по картам
Во-первых, давайте узнаем об итерации через карты. Мы можем использовать 3 метода:
map.keys()
: возвращает итерацию для ключейmap.entries()
: возвращает итерацию для записей[key, value]
map.values()
: возвращает итерацию для значений
Мы можем перебирать коллекцию ключей и значений с помощью метода entries()
, который возвращает итерируемый объект, поэтому мы можем использовать расширенный for loop
вместе с деструктурированием.
Например, ниже мы извлекаем имя и оценку для каждой пары ключ-значение:
'use strict';
//START:DEFINE const scores = new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);
scores.set('Jake', 14); //END:DEFINE
for(const [name, score] of scores.entries()) { console.log(`${name} : ${score}`); }
--> Sara : 12 Bob : 11 Jill : 15 Bruce : 14 Jake : 14
Мы также можем использовать метод forEach
, который является внутренним итератором.
'use strict';
//START:DEFINE const scores = new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);
scores.set('Jake', 14); //END:DEFINE
scores.forEach((score, name) => console.log(`${name} : ${score}`));
--> Sara : 12 Bob : 11 Jill : 15 Bruce : 14 Jake : 14
Первый параметр, который получает функция, — это значение ключа, которое отображается как второй параметр. Тот же метод forEach()
можно использовать для перебора только значений:
'use strict';
//START:DEFINE const scores = new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);
scores.set('Jake', 14); //END:DEFINE
scores.forEach(score => console.log(score));
--> 12 11 15 14 14
Если вы получите только один параметр, это будет значение, а если вы получите два параметра, то он будет обозначать значение и ключ для каждой пары ключ-значение.
Инициализировать карту с итерируемым объектом
Вы также можете передать итерируемый объект конструктору Map()
:
let userRoles = new Map([
[sarah, 'admin'],
[bob, 'editor'],
[jill, 'subscriber']
]);
Получить элемент с карты по ключу
Мы можем получить элементы с карты по ключу с помощью метода get()
:
Но если вы передадите ключ, которого нет на этой карте, он вернет значение undefined.
userRoles.get(sarah); // admin
Но если вы передадите ключ, которого нет на этой карте, он вернет значение undefined.
let foo = {name: 'Foo'};
userRoles.get(foo); //undefined
Получить количество элементов на карте
Мы можем использовать свойство size
, чтобы получить количество элементов на наших картах.
console.log(userRoles.size); // 3
Преобразование ключей карты или значений в массив
Иногда вам может понадобиться работать с массивом вместо итерируемого объекта. Мы можем использовать оператор распространения для преобразования ключей для каждого элемента в новый массив.
var keys = [...userRoles.keys()];
console.log(keys);
Этот фрагмент кода преобразует значения элементов в массив:
var roles = [...userRoles.values()];
console.log(roles);
Другие важные методы Map
clear()
: удаляет элементы из объекта карты.map.set(key, value)
: сохраняет значение по ключуdelete(key)
: удаляет определенный элемент (как указано в ключе)set(key, value)
: устанавливает значение для ключа и возвращает объект карты. Можно связать с другими методами.forEach(callback[, thisArg])
: вызывает обратный вызов для каждой пары ключ-значение в порядке вставки. ПараметрthisArg
является необязательным и устанавливает значениеthis
для каждого обратного вызова.has(key)
: возвращаетtrue
, если значение, связанное с ключом, существует, иначеfalse
.keys()
: возвращает новый итератор с ключами для элементов в порядке вставки.values()
: возвращает новый объект итератора со значениями для каждого элемента в порядке вставки.map.size
: возвращает текущее количество элементов
Что такое set
?
Set
— еще одна новая коллекция, представленная ES6. Класс JavaScript Array
может работать с упорядоченными коллекциями данных, но не так хорошо с неупорядоченными коллекциями или когда значения, хранящиеся в коллекции, уникальны. Вот почему JavaScript представил Set
.
set
— это уникальная коллекция примитивов и объектов, дубликаты не допускаются. Мы можем либо создать пустой набор и добавить объекты, либо мы можем инициализировать набор содержимым итерируемого объекта (например, массива).
Давайте рассмотрим это на примере. Ниже у нас есть набор имен с пятью значениями. Одно из значений не входит в набор из-за дублирования.
'use strict';
//START:CREATE const names = new Set(['Jack', 'Jill', 'Jake', 'Jack', 'Sara']); //END:CREATE
//START:SIZE console.log(names.size); //END:SIZE
--> 4
Мы можем добавить элементы в существующий набор, как показано ниже:
names.add('Matt');
Метод add()
возвращает текущий Set
, что полезно для цепных операций, таких как дополнительные вызовы add()
или других методов Set
:
names.add('Kate')
.add('Kara');
Как использовать set
Как только мы поймем, как создавать наборы, с ними будет легко работать. Во-первых, давайте посмотрим на встроенные функции для наборов:
has()
: чтобы проверить, есть ли в наборе определенный элемент.clear()
: очистить существующий набор или удалить существующий элемент с помощью методаdelete()
.keys()
: чтобы получить все значения из набораentries()
: для перебора набора с использованием расширенного цикла for, как показано ниже:
'use strict';
//START:CREATE const names = new Set(['Jack', 'Jill', 'Jake', 'Jack', 'Sara']); //END:CREATE
//START:ADD names.add('Mike'); //END:ADD
//START:ADD2 names.add('Kate') .add('Kara'); //END:ADD2
console.log(names.has('Brad'));
console.log(names.entries()); console.log(names.keys()); console.log(names.values());
//START:ITERATE1 for(const name of names) { console.log(name); } //END:ITERATE1
--> false [Set Iterator] { 'Jack', 'Jill', 'Jake', 'Sara', 'Mike', 'Kate', 'Kara' } [Set Iterator] { 'Jack', 'Jill', 'Jake', 'Sara', 'Mike', 'Kate', 'Kara' } [Set Iterator] { 'Jack', 'Jill', 'Jake', 'Sara', 'Mike', 'Kate', 'Kara' } Jack Jill Jake Sara Mike Kate Kara
filter
/map
с наборами
Набор еще не предлагает такие методы, как filter()
и map()
, но мы можем создать массив из набора и использовать методы функционального стиля для этого нового массива.
Например, ниже мы используем методы filter()
, map()
и forEach()
, чтобы выбрать только имена, начинающиеся с J
, а затем преобразовать их в верхний регистр.
'use strict';
//START:CREATE const names = new Set(['Jack', 'Jill', 'Jake', 'Jack', 'Sara']); //END:CREATE
//START:ADD names.add('Mike'); //END:ADD
//START:ADD2 names.add('Kate') .add('Kara'); //END:ADD2
//START:FILTER [...names].filter(name => name.startsWith('J')) .map(name => name.toUpperCase()) .forEach(name => console.log(name)); //END:FILTER
--> JACK JILL JAKE
Получить размер набора
Используйте свойство size
объекта Set, чтобы вернуть его размер.
let size = chars.size;
console.log(size);// 3
Удалить элементы из набора
Чтобы удалить элемент из набора, используйте метод delete()
.
chars.delete('f');
console.log(chars); // Set {"a", "b", "c", "d", "e"}
А чтобы удалить все элементы набора, используйте метод clear()
:
chars.clear();
console.log(chars); // Set{}
Вызов функции обратного вызова для каждого элемента
Чтобы вызвать обратный вызов для каждого элемента вашего набора, используйте метод forEach()
.
roles.forEach(role => console.log(role.toUpperCase()));
Другие важные методы Set
new Set(iterable)
: создает набор.set.add(value)
: добавляет заданное значение и возвращает наборset.has(value)
: возвращаетtrue
, если значение существует в наборе, иначе возвращаетfalse
.set.clear()
: удалить все из набора
Практическое упражнение с map
Чтобы закрепить ваши знания, давайте выполним практическое упражнение с картой в JavaScript. Используйте Map
, чтобы получить желаемый результат, как показано ниже. При создании объекта createTodo()
он должен возвращать элемент карты.
Решение этой задачи приведено ниже. Сначала попробуйте сами.
'use strict';
const createTodo = function() { const todo = new Map(); return todo; };
const completedCount = function(map) { return; };
const todo = createTodo(); //Returns a Map
**Решение:
var TestResult = function() { this.succeeded = false; this.reason = ""; this.input = ""; this.expected_output = ""; this.actual_output = ""; }
var executeTests = function(){ var inputs = [0, 1, 2, 5]; var expected_outputs = [0, 1, 4, 25];
var results = [];
for (var i = 0; i < inputs.length; i++) { let result = new TestResult(); result.input = 'square(' + inputs[i] + ')'; result.expected_output = String(expected_outputs[i]);
// Call your Challenge function here. var actual_output = square(inputs[i]); result.actual_output = String(actual_output);
if (actual_output === expected_outputs[i]) { result.succeeded = true; result.reason = "Succeeded" } else { result.succeeded = false; result.reason = "Incorrect Output" }
results.push(result); }
return results; }
Разбивка решения
Начните с создания элемента карты. Объект Map
todo
создается в строке 4 с использованием встроенного класса. Вы можете видеть, что объект карты todo
вызывает Map.get()
с разными ключами, чтобы получить их значения. Это означает, что нам нужно добавить все ключи и значения.
Мы добавляем новый элемент в todo
с ключами и соответствующими значениями. В строках 5-7 мы добавляем новые элементы, задавая значения для ключей.
Для completedCount()
мы определяем новую функцию с параметром объекта карты. Функция вернет количество выполненных задач. Итак, по сути, мы фильтруем все значения элементов в объекте карты, чтобы получить элементы со значением, равным done
(см. строку 14).
В строке 15 свойство length используется для получения количества специальных элементов.
Что изучать дальше
Map и set — ценные дополнения к JavaScript, они сделают ваш код чище и проще в обслуживании. Теперь, когда у вас есть четкое представление о карте и наборе, вы готовы заняться другими функциями, добавленными в ES6 и более поздних версиях.
Вот некоторые концепции, которые следует рассмотреть для модернизации вашего JavaScript:
- Async и Await (обещания)
- Метапрограммирование
- Литералы объектов
- Стрелочные функции
Чтобы быстро освоить функции JavaScript, ознакомьтесь с курсом Educative Открывая заново JavaScript: ES6, ES7 и ES8.. Этот курс охватывает современные функции JavaScript, чтобы сделать ваш код элегантным, лаконичным, выразительным и менее подвержен ошибкам. Вы начнете с изучения основных функций современного JavaScript, а во второй половине вы углубитесь в сложные функции, такие как деструктурирование, литералы, наследование, модули, промисы и метапрограммирование.
К концу этого курса вы сможете добавлять новые функции с минимальными усилиями и писать код более эффективно!
Удачного обучения!
Продолжить чтение о JavaScript на Educative
- Методы массива JavaScript: как использовать карту и уменьшить
- Повысьте свои навыки JavaScript с помощью 10 задач по программированию
- Версии JavaScript: как JavaScript изменился за эти годы
Начать обсуждение
Что вы надеетесь узнать о JavaScript дальше? Была ли эта статья полезна? Дайте нам знать в комментариях ниже!