This commit is contained in:
Ilya Kantor 2015-07-07 19:32:23 +03:00
parent c978fe73c1
commit ff23414aed

View file

@ -24,9 +24,13 @@ map
// в обычном объекте это было бы одно и то же
alert( map.get(1) ); // 'num1'
alert( map.get('1') ); // 'str1'
alert( map.size ); // 3
```
Как видно из примера выше, для сохранения и чтения значений используются методы `get` и `set`, причём `set` можно чейнить.
Как видно из примера выше, для сохранения и чтения значений используются методы `get` и `set`, причём `set` можно чейнить. И ключи и значения сохраняются "как есть", без преобразований типов.
Свойство `map.size` хранит общее количество записей в `map`.
**При создании `Map` можно сразу инициализовать списком значений.**
@ -62,11 +66,14 @@ alert( visitsCountMap.get(user) ); // 123
[smart header="Как map сравнивает ключи"]
Для проверки значений на эквивалентность используется алгоритм [SameValueZero](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-samevaluezero). Он аналогичен строгому равенству `===`, отличие -- в том, что `NaN` считается равным `NaN`.
Этот алгоритм жёстко фиксирован в стандарте, его нельзя изменять или задавать свою функцию для него.
[/smart]
Для удаления записей используется метод:
Для удаления записей:
<ul>
<li>`map.delete(key)` -- возвращает `true`, если ключ существовал, иначе `false`.</li>
<li>`map.delete(key)` удаляет запись с ключом `key`, возвращает `true`, если такая запись была, иначе `false`.</li>
<li>`map.clear()` -- удаляет все записи, очищает `map`.</li>
</ul>
Для проверки существования ключа:
@ -122,6 +129,10 @@ for(let entry of recipeMap) { // то же что и recipeMap.entries()
}
```
[smart header="Перебор идёт в том же порядке, что и вставка"]
Перебор осуществляется в порядке вставки. Объекты `Map` гарантируют это, в отличие от обычных объектов `Object`.
[/smart]
Кроме того, у `Map` есть стандартный методы `forEach`, аналогичный массиву:
```js
@ -140,17 +151,134 @@ recipeMap.forEach( (value, key, map) => {
```
Есть и другие методы:
У `Map` есть и другие свой методы:
<ul>
<li>`map.size()` -- количество записей в
<li>`map.size()` -- возвращает количество записей,</li>
<li>`map.clear()` -- удаляет все записи.</li>
</ul>
## Set
`Set` -- коллекция для хранения множества значений, причём каждое значение может встречаться лишь один раз.
Например, к нам приходят посетители, и мы хотели бы сохранять всех, кто пришёл. Повторные визиты не должны приводить к дубликатам.
`Set` для этого отлично подходит:
```js
//+ run
'use strict';
let set = new Set();
let vasya = {name: "Вася"};
let petya = {name: "Петя"};
let dasha = {name: "Даша"};
// посещения
set.add(vasya);
set.add(petya);
set.add(dasha);
set.add(vasya);
set.add(petya);
alert( set.size ); // 3
set.forEach( user => alert(user.name ) ); // Вася, Петя, Даша
```
В примере выше многократные добавления одного и того же объекта в `set` не создают лишних копий.
Альтернатива `Set` -- это массивы с поиском дубликата при каждом добавлении, но это гораздо хуже по производительности. Или же объекты, где в качестве ключа выступает какой-нибудь уникальный идентификатор посетителя. Но это менее удобно, чем простой и наглядный `Set`.
Основные методы:
<ul>
<li>`set.add(item)` -- добавляет в коллекцию `item`, возвращает `set` (чейнится).</li>
<li>`set.delete(item) -- удаляет `item` из коллекции, возвращает `true`, если он там был, иначе `false`.</li>
<li>`set.has(item)` -- возвращает `true`, если `item` есть в коллекции, иначе `false`.</li>
<li>`set.clear()` -- очищает `set`.</li>
</ul>
Перебор `Set` осуществляется через `forEach` или `for..of` аналогично `Map`:
```js
//+ run
'use strict';
let set = new Set(["апельсины", "яблоки", "бананы"]);
// то же, что: for(let value of set)
set.forEach((value, valueAgain, set) => {
alert(value); // апельсины, затем яблоки, затем бананы
});
```
Заметим, что в `Map` у функции в `.forEach` три аргумента: ключ, значение, объект `map`.
В `Set` для совместимости с `Map` сделано похожим образом -- у `.forEach`-функции также три аргумента. Но первые два всегда совпадают и содержат очередное значение множества.
## WeakMap и WeakSet
`WeakSet` -- особый вид `Set` не препятствующий сборщику мусора. То же самое -- `WeakMap` для `Map`.
То есть, если некий объект присутствует только в `WeakSet/WeakMap` -- он удаляется из памяти.
Это нужно для тех ситуаций, когда сами объекты используются где-то в другом месте кода, а здесь мы хотим хранить для них "вспомогательные" данные, существующие лишь пока жив объект.
Например, у нас есть элементы на странице или, к примеру, пользователи, и мы хотим хранить для них вспомогательную инфомацию, например обработчики событий или просто данные, но действительные лишь пока объект, к которому они относятся, существует.
Если поместить такие данные в `WeakMap`, а объект сделать ключом, то они будут автоматически удалены из памяти, когда удалится элемент.
Например:
```js
// текущие активные пользователи
let activeUsers = [
{name: "Вася"},
{name: "Петя"},
{name: "Маша"}
];
// вспомогательная информация о них,
// которая напрямую не входит в объект юзера,
// и потому хранится отдельно
let weakMap = new WeakMap();
weakMap[activeUsers[0]] = 1;
weakMap[activeUsers[1]] = 2;
weakMap[activeUsers[2]] = 3;
alert( weakMap[activeUsers[0]].name ); // Вася
activeUsers.splice(0, 1); // Вася более не активный пользователь
// weakMap теперь содержит только 2 элемента
activeUsers.splice(0, 1); // Петя более не активный пользователь
// weakMap теперь содержит только 1 элемент
```
TODO WRITE MORE
ToDo