Коллекции
Этот раздел содержит обзор коллекций Set и словарей Map (en-US) — встроенных структур данных с доступом по ключу.
Словари
Тип Map
Map (en-US) — реализация простого ассоциативного массива (словаря). Он содержит данные в виде набора пар ключ/значение(ключи уникальны) и предоставляет методы для доступа и манипулирования этими данными.
Также как и объект, словарь позволяет
- получать значение по ключу, а также проверять наличие ключа
- добавлять/удалять пары ключ/значение
- перезаписывать значение по ключу (ключи уникальны).
- итерироваться по ключам
Словари, как специализированная структура данных, имеют существенные преимущества по сравнению с объектами:
- Ключи словаря могут быть любого типа (а не только строки).
- Словарь хранит свой размер (не надо вычислять).
- Натуральный порядок обхода элементов ( в порядке добавления) с помощью for. of .
- Словарь не подмешивает ключи из прототипа (в отличие от объекта).
В следующем примере приведены основные операции со словарём:
var sayings = new Map(); sayings.set("dog", "woof"); sayings.set("cat", "meow").set("elephant", "toot"); //вызов функции .set возвращает Map, поэтому set можно объединять в цепочки sayings.set("dog", "гав-гав"); // заменить значение по ключу sayings.size; // 3 sayings.get("fox"); // undefined sayings.has("bird"); // false sayings.delete("dog"); for (var [key, value] of sayings) console.log(key + " goes " + value); > // "cat goes meow" // "elephant goes toot"
Больше примеров и полное описание на странице справочника Map (en-US) .
Тип WeakMap
WeakMap это специальный вид словаря, ключами которого могут быть только объекты, причём ссылки на них в WeakMap являются слабыми (не учитываются сборщиком мусора (garbage collector GC)).
Примечание: Интерфейс WeakMap совпадает с Map , единственное отличие — ключи WeakMap нельзя итерировать (т.e. нельзя получить список ключей). Это понятно, поскольку в таком случае возникла бы неопределённость с достоверностью этого списка в зависимости от состояния garbage collection.
Больше примеров, полное описание, а также обсуждение «Зачем WeakMap?» на странице справочника WeakMap .
Отметим, что WeakMap, в частности, может элегантно использоваться для упаковки приватных данных или деталей реализации. Следующий пример из статьи Nick Fitzgerald «Hiding Implementation Details with ECMAScript 6 WeakMaps». Приватная часть сохраняется как значение в privates и имеет время жизни такое же как и сущность класса. Сам класс и его методы публичны; прочее недоступно извне модуля:
const privates = new WeakMap(); export class Public() constructor() const me = // Приватные данные идут здесь >; // 'me' будет освобождён вместе с 'this' . privates.set(this, me); > method () const me = privates.get(this); // Сделайте что-нибудь с приватными данными в 'me'. > >
Коллекции
Тип Set
Set реализация коллекции — структура данных, которая содержит список уникальных элементов в порядке их добавления.
В следующем примере приведены основные операции по работе с коллекцией Set:
var mySet = new Set(); mySet.add(1); mySet.add("some text"); mySet.add("foo"); mySet.has(1); // true mySet.delete("foo"); mySet.size; // 2 for (let item of mySet) console.log(item); // 1 // "some text"
Больше примеров и полное описание на странице справочника Set
Преобразования между Array и Set
Можно создать Array из Set с помощью Array.from или используя spread operator.
В свою очередь, конструктор Set может принимать Array в качестве аргумента.
Примечание: Поскольку Set структура работает с уникальными значениями, любые повторяющиеся элементы из Array будут проигнорированы.
.from(mySet); [. mySet2]; mySet2 = new Set([1, 2, 3, 4]);
Сравнение Array и Set
Словари, как специализированная структура данных, имеют существенные отличия по сравнению с массивами:
- Set.has работает быстрее чем Array.indexOf .
- можно удалять элементы по значению (а не по индексу как массивах).
- NaN обрабатывается корректно.
- поддерживается уникальность значений.
Тип WeakSet
WeakSet это специальный вид коллекции, элементами которой могут быть только объекты. Ссылки на эти объекты в WeakSet являются слабыми (не учитываются сборщиком мусора (garbage collector GC)).
Примечание: Элементы WeakSet уникальны и могут быть добавлены только один раз, также как и в Set .
Основные отличия от Set :
- WeakSet это коллекция объектов ( примитивные значения не могут быть добавлены).
- WeakSet нельзя итерировать. А также нельзя получить список (итератор) элементов.
Использование WeakSet достаточно специфическое. Пользуясь тем, что они не могут создавать утечек памяти, в них можно, например, безопасно помещать ссылки на DOM-элементы.
Больше примеров и полное описание на странице справочника WeakSet
Проверка на равенство в Map и Set
Сравнение на равенство ключей в Map objects или объектов в Set основано на «same-value-zero algorithm»:
- алгоритм сравнения в целом совпадает с оператором === .
- -0 и +0 считаются равными (в отличие от === ).
- NaN считается равным самому себе (в отличие от === ).
- « Предыдущая статья
- Следующая статья »
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 7 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.
как получить ключи объекта js
Для получения массива ключей объекта служит метод Object.keys() . В качестве аргумента передаётся объект, ключи которого мы хотим получить.
const obj = 1: 'a', 2: 'b', 3: 'c', 4: 'd', anotherKey: 'some value', >; const keys = Object.keys(obj); console.log(keys); // => [ '1', '2', '3', '4', 'anotherKey' ]
Перебор объекта в JavaScript
В этом посте мы рассмотрим как в JS перебрать объект с помощью цикла и методов. Методы перебора массива мы рассматривали в этой статье.
Мы рассмотрим следующие варианты:
- for in — цикл по объекту. Можно получить и ключ и значение.
- Object.entries() — метод, возвращающий массив пар [key, value]
- Object.keys() — метод, который возвращает массив ключей [key1, key2]
- Object.values() — метод, который возвращает массив значений [value1, value2]
For … in
Начнем с простого примера, допустим у нас есть объект user
const user =
Если мы знаем все свойства этого объекта, то мы могли бы их просто вывести так:
console.log(user.name); console.log(user.age); // и т.д.
Но что, если мы не знаем сколько у него сейчас свойств и какие свойства есть, а нам нужно их все отобразить. В данном случае нам и понадобиться цикл для прохода по этому объекту
for (let key in user) < console.log(key + ' - ' + user[key]); >// В консоли мы увидим следующее: // name - John // age - 30 // position - manager // salary - 5000
В переменную key мы получаем на каждой итерации ключ, а для того чтобы получить значение по данному ключу, мы используем user[key] .
Обратите внимание, что мы не можем написать просто user.key , т.к. у нашего объекта нет такого свойства, key — это переменная, которую мы задали для прохода по объекту в цикле (кстати, мы также можем сделать ее const вместо let , это не имеет значения). Поэтому мы обращаемся именно через квадратные скобки []
В другом примере, рассмотрим вариант когда нам те же данные нужно вывести и добавить к определeнному div
Еще пару моментов, которые касаются этого цикла. Первое, сортировка ключей происходит в порядке их добавления, если ключи это обычные строки. Если ключи это числа (не важно 9 или «9»), тогда они будут выводиться в порядке возрастания. Допустим, есть объект с постами, где ключ это id поста:
const posts = < 2: 'Второй пост', 3: 'Третий пост', 1: 'Первый пост' >console.log(posts); //
Так часто приходится делать в случае, когда вам нужно будет вытащить пост по ID, это будет быстрее чем перебирать весь массив постов.
Второй нюанс, это то что данный цикл перебирает все свойства в цепочке Prototype:
const user = < name: 'John', age: 30 >const user1 = < lastName: 'Doe', role: 'admin' >user1.__proto__ = user; for (let key in user1) < console.log(key); >// Результат в консоли // lasName, role, name, age
Для того, чтобы вывести только свойства конкретного объекта, вам придется воспользоваться методом hasOwnProperty (более детально об этом методе), чтобы убедиться что данное свойство принадлежит только итерируемому объекту:
for (let key in user1) < if (user1.hasOwnProperty(key)) < console.log(key); >> // lastName, role
Object.entries() — пара ключ значение из объекта
Данный метод вернет массив, где каждый элемент массива будет парой [ключ, значение]
const user = < name: 'John', age: 30, role: 'Administrator' >const objEntries = Object.entries(user); console.log(objEntries); // [ ['name', 'John'], ['age', 30], ['role', 'Administrator'] ]
Важно, обратите внимание на вызов данного метода. Нельзя просто написать user.entries()
Из нашего примера видно, что в переменной objEntries будет массив состоящий из 3 других массивов. Дальше в зависимости от того, что вам нужно в результате, вы можете воспользоваться методами массивов.
Object.keys() — получаем ключи из объекта
Данный метод возвращает массив ключей объекта. Если рассмотреть на том же примере с объектом user, то получим:
const objKeys = Object.keys(user); console.log(objKeys); // [ 'name', 'age', 'role' ]
Данный метод можно использовать для определения количества элементов в объекте:
console.log(Object.keys(user).length); // 3
Это упрощенная версия, более детально как проверить количество элементов в объекте или проверить объект на пустоту можете ознакомиться по ссылке.
Object.values() — получаем массив значений из объекта
Как вы уже наверное догадались, данный метод возвращает массив со значениями:
const user = < name: 'John', age: 30, role: 'Administrator' >const objValues = Object.values(user); console.log(objValues); // [ 'John', 30, 'Administrator' ]
Тут думаю ничего сложного, но если остались вопросы пишите в комментариях.
Ваши вопросы и комментарии:
Свежие записи
- MySQL IS NULL — проверка поля на NULL
- MySQL LIKE — поиск по паттерну
- Between MySQL — оператор для выборки по диапазону значений
- MySQL IN и NOT IN — несколько условий
- MySQL WHERE — синтаксис и примеры
Копирование материалов разрешено только с ссылкой на источник Web-Dev.guru
2024 © Все права защищены.
Map и Set
Сейчас мы знаем о следующих сложных структурах данных:
- Объекты для хранения именованных коллекций.
- Массивы для хранения упорядоченных коллекций.
Но этого не всегда достаточно для решения повседневных задач. Поэтому также существуют Map и Set .
Map
Map – это коллекция ключ/значение, как и Object . Но основное отличие в том, что 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 map = new Map(); map.set("1", "str1"); // строка в качестве ключа map.set(1, "num1"); // цифра как ключ map.set(true, "bool1"); // булево значение как ключ // помните, обычный объект Object приводит ключи к строкам? // Map сохраняет тип ключей, так что в этом случае сохранится 2 разных значения: alert(map.get(1)); // "num1" alert(map.get("1")); // "str1" alert(map.size); // 3
Как мы видим, в отличие от объектов, ключи не были приведены к строкам. Можно использовать любые типы данных для ключей.
map[key] это не совсем правильный способ использования Map
Хотя map[key] также работает, например, мы можем установить map[key] = 2 , в этом случае map рассматривался бы как обычный JavaScript объект, таким образом это ведёт ко всем соответствующим ограничениям (только строки/символьные ключи и так далее).
Поэтому нам следует использовать методы map : set , get и так далее.
Map может использовать объекты в качестве ключей.
let john = < name: "John" >; // давайте сохраним количество посещений для каждого пользователя let visitsCountMap = new Map(); // объект john - это ключ для значения в объекте Map visitsCountMap.set(john, 123); alert(visitsCountMap.get(john)); // 123
Использование объектов в качестве ключей – одна из наиболее заметных и важных функций Map . Это то что невозможно для Object . Строка в качестве ключа в Object – это нормально, но мы не можем использовать другой Object в качестве ключа в Object .
Давайте попробуем заменить Map на Object :
let john = < name: "John" >; let ben = < name: "Ben" >; let visitsCountObj = <>; // попробуем использовать объект visitsCountObj[ben] = 234; // пробуем использовать объект ben в качестве ключа visitsCountObj[john] = 123; // пробуем использовать объект john в качестве ключа, при этом объект ben будет замещён // Вот что там было записано! alert( visitsCountObj["[object Object]"] ); // 123
Так как visitsCountObj является объектом, он преобразует все ключи Object , такие как john и ben , в одну и ту же строку «[object Object]» . Это определенно не то, чего мы хотим.
Как объект Map сравнивает ключи
Чтобы сравнивать ключи, объект Map использует алгоритм SameValueZero. Это почти такое же сравнение, что и === , с той лишь разницей, что NaN считается равным NaN . Так что NaN также может использоваться в качестве ключа.
Этот алгоритм не может быть заменён или модифицирован.
Цепочка вызовов
Каждый вызов map.set возвращает объект map, так что мы можем объединить вызовы в цепочку:
map.set("1", "str1") .set(1, "num1") .set(true, "bool1");
Перебор Map
Для перебора коллекции Map есть 3 метода:
- map.keys() – возвращает итерируемый объект по ключам,
- map.values() – возвращает итерируемый объект по значениям,
- map.entries() – возвращает итерируемый объект по парам вида [ключ, значение] , этот вариант используется по умолчанию в for..of .
let recipeMap = new Map([ ["огурец", 500], ["помидор", 350], ["лук", 50] ]); // перебор по ключам (овощи) for (let vegetable of recipeMap.keys()) < alert(vegetable); // огурец, помидор, лук >// перебор по значениям (числа) for (let amount of recipeMap.values()) < alert(amount); // 500, 350, 50 >// перебор по элементам в формате [ключ, значение] for (let entry of recipeMap) < // то же самое, что и recipeMap.entries() alert(entry); // огурец,500 (и так далее) >
Используется порядок вставки
В отличие от обычных объектов Object , в Map перебор происходит в том же порядке, в каком происходило добавление элементов.
Кроме этого, Map имеет встроенный метод forEach , схожий со встроенным методом массивов Array :
// выполняем функцию для каждой пары (ключ, значение) recipeMap.forEach((value, key, map) => < alert(`$: $`); // огурец: 500 и так далее >);
Object.entries: Map из Object
При создании Map мы можем указать массив (или другой итерируемый объект) с парами ключ-значение для инициализации, как здесь:
// массив пар [ключ, значение] let map = new Map([ ['1', 'str1'], [1, 'num1'], [true, 'bool1'] ]); alert( map.get('1') ); // str1
Если у нас уже есть обычный объект, и мы хотели бы создать Map из него, то поможет встроенный метод Object.entries(obj), который получает объект и возвращает массив пар ключ-значение для него, как раз в этом формате.
Так что мы можем создать Map из обычного объекта следующим образом:
let obj = < name: "John", age: 30 >; let map = new Map(Object.entries(obj)); alert( map.get('name') ); // John
Здесь Object.entries возвращает массив пар ключ-значение: [ [«name»,»John»], [«age», 30] ] . Это именно то, что нужно для создания Map .
Object.fromEntries: Object из Map
Мы только что видели, как создать Map из обычного объекта при помощи Object.entries(obj) .
Есть метод Object.fromEntries , который делает противоположное: получив массив пар вида [ключ, значение] , он создаёт из них объект:
let prices = Object.fromEntries([ ['banana', 1], ['orange', 2], ['meat', 4] ]); // prices = < banana: 1, orange: 2, meat: 4 >alert(prices.orange); // 2
Мы можем использовать Object.fromEntries , чтобы получить обычный объект из Map .
К примеру, у нас данные в Map , но их нужно передать в сторонний код, который ожидает обычный объект.
Вот как это сделать:
let map = new Map(); map.set('banana', 1); map.set('orange', 2); map.set('meat', 4); let obj = Object.fromEntries(map.entries()); // создаём обычный объект (*) // готово! // obj = < banana: 1, orange: 2, meat: 4 >alert(obj.orange); // 2
Вызов map.entries() возвращает итерируемый объект пар ключ/значение, как раз в нужном формате для Object.fromEntries .
Мы могли бы написать строку (*) ещё короче:
let obj = Object.fromEntries(map); // убрать .entries()
Это то же самое, так как Object.fromEntries ожидает перебираемый объект в качестве аргумента, не обязательно массив. А перебор map как раз возвращает пары ключ/значение, так же, как и map.entries() . Так что в итоге у нас будет обычный объект с теми же ключами/значениями, что и в map .
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.add() с одним и тем же значением ничего не происходит, за счёт этого как раз и получается, что каждое значение появляется один раз.
Например, мы ожидаем посетителей, и нам необходимо составить их список. Но повторные визиты не должны приводить к дубликатам. Каждый посетитель должен появиться в списке только один раз.
Множество Set – как раз то, что нужно для этого:
let set = new Set(); let john = < name: "John" >; let pete = < name: "Pete" >; let mary = < name: "Mary" >; // считаем гостей, некоторые приходят несколько раз set.add(john); set.add(pete); set.add(mary); set.add(john); set.add(mary); // set хранит только 3 уникальных значения alert(set.size); // 3 for (let user of set) < alert(user.name); // John (потом Pete и Mary) >
Альтернативой множеству Set может выступать массив для хранения гостей и дополнительный код для проверки уже имеющегося элемента с помощью arr.find. Но в этом случае будет хуже производительность, потому что arr.find проходит весь массив для проверки наличия элемента. Множество Set лучше оптимизировано для добавлений, оно автоматически проверяет на уникальность.
Перебор объекта Set
Мы можем перебрать содержимое объекта set как с помощью метода for..of , так и используя forEach :
let set = new Set(["апельсин", "яблоко", "банан"]); for (let value of set) alert(value); // то же самое с forEach: set.forEach((value, valueAgain, set) => < alert(value); >);
Заметим забавную вещь. Функция в forEach у Set имеет 3 аргумента: значение value , потом снова то же самое значение valueAgain , и только потом целевой объект. Это действительно так, значение появляется в списке аргументов дважды.
Это сделано для совместимости с объектом Map , в котором колбэк forEach имеет 3 аргумента. Выглядит немного странно, но в некоторых случаях может помочь легко заменить Map на Set и наоборот.
Set имеет те же встроенные методы, что и Map :
- set.keys() – возвращает перебираемый объект для значений,
- set.values() – то же самое, что и set.keys() , присутствует для обратной совместимости с Map ,
- set.entries() – возвращает перебираемый объект для пар вида [значение, значение] , присутствует для обратной совместимости с Map .
Итого
Map – коллекция пар ключ-значение.
Методы и свойства:
- new Map([iterable]) – создаёт коллекцию, можно указать перебираемый объект (обычно массив) из пар [ключ,значение] для инициализации.
- 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 – возвращает текущее количество элементов.
Отличия от обычного объекта Object :
- Что угодно может быть ключом, в том числе и объекты.
- Есть дополнительные методы, свойство size .
Set – коллекция уникальных значений, так называемое «множество».
Методы и свойства:
- new Set(iterable) – создаёт Set , можно указать перебираемый объект со значениями для инициализации.
- set.add(value) – добавляет значение (если оно уже есть, то ничего не делает), возвращает тот же объект set .
- set.delete(value) – удаляет значение, возвращает true если value было в множестве на момент вызова, иначе false .
- set.has(value) – возвращает true , если значение присутствует в множестве, иначе false .
- set.clear() – удаляет все имеющиеся значения.
- set.size – возвращает количество элементов в множестве.
Перебор Map и Set всегда осуществляется в порядке добавления элементов, так что нельзя сказать, что это – неупорядоченные коллекции, но поменять порядок элементов или получить элемент напрямую по его номеру нельзя.
Задачи
Фильтрация уникальных элементов массива
важность: 5
Допустим, у нас есть массив arr .
Создайте функцию unique(arr) , которая вернёт массив уникальных, не повторяющихся значений массива arr .
function unique(arr) < /* ваш код */ >let values = ["Hare", "Krishna", "Hare", "Krishna", "Krishna", "Krishna", "Hare", "Hare", ":-O" ]; alert( unique(values) ); // Hare,Krishna,:-O
P.S. Здесь мы используем строки, но значения могут быть любого типа.
P.P.S. Используйте Set для хранения уникальных значений.
function unique(arr)