- Операторы
- Управляющие инструкции
- JS Объекты
- Array
- Boolean
- Date
- Error
- Function
- Global
- JSON
- Math
- Number
- Object
- RegExp
- String
- Unicode
- Symbol
- Итераторы и генераторы
- Map и WeakMap
- Set и WeakSet
- Локализация
- браузер BOM
- HTML DOM
- События
- HTML Объекты
- Промисы, async/await
- Сетевые запросы
- Бинарные данные и файлы
- Модули
- Классы
- Разное
Map и WeakMap
Map
Map – это коллекция ключ/значение ([key, value]) как и Object. Но основное отличие в том, что Map позволяет использовать ключи любого типа.
Методы и свойства
let map = new Map( [iterable] )
Метод Map() создает новый Map-объект
Параметр
- iterable
- Необязательный. Массив или другой итерируемый объект, элементы которого являются пары ключ-значение. Например:
let myMap = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ])
map.size
Свойство size возвращает текущее количество элементов.
let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); Alert ( map.size );
map.set( key, value )
Метод set() записывает по ключу
keyзначениеvalueи возвращает этот же объект.let map = new Map(); map.set('bar', 'foo'); map.set(1, 'foobar'); map.set('bar', 'baz'); // обновить элементЭтот же пример можно записать так:
let map = new Map(); map.set('bar', 'foo') .set(1, 'foobar'); .set('bar', 'baz'); // обновить элементMap может использовать объекты в качестве ключей.
let john = { name: "John" }; // давайте сохраним количество посещений для каждого пользователя let visitsCountMap = new Map(); // объект john - это ключ для значения в объекте Map visitsCountMap.set(john, 123); Alert(visitsCountMap.get(john)); // 123map.get( key )
Метод get() возвращает значение по ключу или
undefined, если ключkeyотсутствует.let map = new Map(); map.set('bar', 'foo'); Alert( map.get('bar') + '\n' + map.get('bad') );map.has( key )
Метод has() возвращает
true, если ключkeyприсутствует в коллекции, иначеfalse.let map = new Map([ ['bar', "foo"] ]); Alert( map.has('bar') + '\n' + map.has('bad') );map.delete( key )
Метод delete() удаляет элемент по ключу
keyи возвращаетtrue, если элемент в объектеMapсуществовал и был удален, илиfalse, если элемент не существует.let map = new Map(); map.set('bar', 'foo'); Alert( map.delete('bar') + '\n' + map.delete('bar') );map.clear()
Метод clear() очищает коллекцию от всех элементов и возвращает
undefined.let map = new Map(); map.set( 'bar', 'baz' ).set( 1, 'foo' ); let s = map.size + '\n' + map.has( 'bar' ); map.clear(); Alert( s+'\n\n' + map.size + '\n' + map.has( 'bar' ) );
map.keys()
Метод keys() возвращает итерируемый объект по ключам.
let map = new Map(); map.set('0', 'foo') .set(1, 'bar') .set({}, 'baz'); var Iter = map.keys(); Alert (` ${ Iter.next().value } ${ Iter.next().value } ${ Iter.next().value } `);map.values()
Метод values() возвращает итерируемый объект по по значениям.
let map = new Map(); map.set('0', 'foo') .set(1, 'bar') .set({}, 'baz'); var Iter = map.values(); Alert (` ${ Iter.next().value } ${ Iter.next().value } ${ Iter.next().value } `);map.entries()
Метод entries() возвращает итерируемый объект по парам вида
[ключ, значение], этот вариант используется по умолчанию вfor..of.let map = new Map(); map.set('0', 'foo') .set(1, 'bar') .set({}, 'baz'); var Iter = map.entries(); let s = ` ${ Iter.next().value } ${ Iter.next().value } ${ Iter.next().value } \n`; for (let k of map) { // то же самое, что и map.entries() s += k+'\n'; } s+='\n'; for (let [key, value] of map) { s += `${key}: ${value}\n`; } Alert (s);map[Symbol.iterator]
Метод map[Symbol.iterator] возвращает новый объект Iterator, который содержит
массив[key, value]для каждого элемента вMap-объектев порядке вставки.let map = new Map(); map.set('0', 'foo') .set(1, 'bar') .set({}, 'baz'); var Iter = map[Symbol.iterator](); // тоже, что map.entries() let s = ` ${ Iter.next().value } ${ Iter.next().value } ${ Iter.next().value } \n`; for (let k of map) { // то же самое, что и map.entries() s += k+'\n'; } Alert (s);map.forEach(callbackFn[, thisArg])
Метод forEach() Вызывается функцию
callbackFnодин раз для каждой пары ключ-значение (key,value), присутствующей в Map-объекте, в порядке вставки. Если указан параметрthisArg, он будет использоваться в качествеthisзначения для каждого обратного вызова. Метод возвращаетundefinedМетод forEach() выполняет
callbackпо одному разу для каждого значения, которое находится в объекте Set. Функция не будет выполняться для значений, которые были удалены. Тем не менее функция выполнится с элементами, значение которыхundefined.callbackвызывается с тремя аргументами:1. значение элемента
2. ключ элемента
3. Set-объект обходаlet s = ''; function MapElements(value, key, map) { s += `map.get('${key}') = ${value}\n`; } map = new Map([['foo', 3], ['bar', {}], ['baz', undefined]]); map.forEach(MapElements); Alert (s);
Использование NaN в качестве ключей Map
Чтобы сравнивать ключи, объект Map использует алгоритм SameValueZero. Это почти такое же сравнение, что и ===, с той лишь разницей, что NaN считается равным NaN. Так что NaN также может использоваться в качестве ключа.
WeakMap
WeakMap представляет развитие коллекции Map. Первое отличие от Map в том, что ключи в WeakMap должны быть объектами, а не примитивными значениями.
Синтаксис
weakMap = new WeakMap([iterable])
Параметры
- iterable
- Необязательный. Может быть массивом или любым другим итерируемым объектом, элементы которого являются парами ключ-значение (массивы из двух элементов). Каждая пара ключ-значение будет добавлена во вновь созданный экземпляр WeakMap.
Nullобрабатывается какundefined.
WeakMap не поддерживает перебор и методы keys(), values(), entries(), так что нет способа взять все ключи или значения из неё.
В WeakMap присутствуют только следующие методы:
weakMap.set(key, value). Метод записывает по ключуkeyзначениеvalueи возвращает этот же объект.weakMap.get(key). Возвращает значение по ключу илиundefined, если ключkeyотсутствует.weakMap.delete(key). Возвращаетtrue, если элемент в объекте WeakMap был успешно удален илиfalse, если ключ не найден в WeakMap или если ключ не является объектом.weakMap.has(key). Возвращаетtrue, если ключkeyприсутствует в коллекции, иначеfalse
Пример использования объекта WeakMap
const wm1 = new WeakMap(),
wm2 = new WeakMap(),
wm3 = new WeakMap();
const o1 = {},
o2 = function(){},
o3 = window,
o4 = [1, 2, 3];
wm1.set(o1, 37);
wm1.set(o2, 'azerty');
wm2.set(o1, o2); // значением может быть что угодно, включая объект или функцию
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // ключами и значениями могут быть объекты. Даже WeakMap-ами
wm1.get(o2); // 'azerty'
wm2.get(o2); // undefined, нет значения для o2 в wm2
wm2.get(o3); // undefined, это установленное значение
wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (даже если значение равно 'undefined')
wm3.set(o1, 37);
wm3.get(o1); // 37
wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false
Вторым отличием от Map - cлабые (weaks) ссылки.
Объекты передаются в WeakMap по ссылке. И когда объект перестает существовать в силу различных причин, он удаляется из WeakMap. Рассмотрим следующий пример:
let jsCode = {code: "js"},
tsCode = {code: "ts"};
let js = {lang: "JavaScript"},
ts = {lang: "TypeScript"};
const weakMap = new WeakMap([[jsCode, js], [tsCode, ts]]);
jsCode = null;
Alert(weakMap); // WeakMap {{code: "js"} => {lang: "JavaScript"}, {code: "ts"} => {lang: "TypeScript"}}
Alert("Некоторая работа");
const timerId = setTimeout(function(){
Alert(weakMap); // WeakMap {{code: "ts"} => {lang: "TypeScript"}}
clearTimeout(timerId);
}, 10000);В данном случае сначала объект WeakMap хранит ссылки на два элемента с ключами jsCode и tsCode. Далее для переменной jsCode устанавливается значение null.
jsCode = null;
Это приведет к тому, что спустя некоторое время начальное значение этой переменной будет удалено сборщиком мусора JavaScript.
Причем если сразу после этого мы посмотрим на содержимое weakMap, то увидим, что объект с ключом jsCode в нем еще присутствует. Однако спустя некоторое время ссылка будет удалена из weakMap. Для эмуляции прошествия времени здесь используется функция setTimeout, которая выводит на консоль содержимое weakMap через 10 секунд (конкретный период времени, через который сборщик мусора удалит значение, может отличаться)
Теперь сравним с тем, что произойдет, если вместо WeakMap использовать Map:
let jsCode = {code: "js"},
tsCode = {code: "ts"};
let js = {lang: "JavaScript"},
ts = {lang: "TypeScript"};
const map = new Map([[jsCode, js], [tsCode, ts]]);
jsCode = null;
Alert(map); // Map(2) {{code: "js"} => {lang: "JavaScript"}, {code: "ts"} => {lang: "TypeScript"}}
Alert("Некоторая работа");
const timerId = setTimeout(function(){
Alert(map); // Map(2) {{code: "js"} => {lang: "JavaScript"}, {code: "ts"} => {lang: "TypeScript"}}
clearTimeout(timerId);
}, 10000);В случае с Map даже спустя некоторое время мы увидим, что в объекте Map до сих пор присутствует объект, для которого было установлено значение null