|
| 1 | + |
| 2 | +# Set, Map, WeakSet и WeakMap |
| 3 | + |
| 4 | +Новые типы коллекций в JavaScript: `Set`, `Map`, `WeakSet` и `WeakMap`. |
| 5 | + |
| 6 | + |
| 7 | +## Map |
| 8 | + |
| 9 | +`Map` -- коллекция для хранения записей вида `ключ: значение`. |
| 10 | + |
| 11 | +В отличие от объектов, в которых ключами могут быть только строки, в `Map` ключом может быть произвольное значение, например: |
| 12 | + |
| 13 | +```js |
| 14 | +//+ run |
| 15 | +'use strict'; |
| 16 | + |
| 17 | +let map = new Map(); |
| 18 | + |
| 19 | +map.set('1', 'str1'); // строка |
| 20 | +map |
| 21 | + .set(1, 'num1') // число |
| 22 | + .set(true, 'bool1'); // булевое |
| 23 | + |
| 24 | +// в обычном объекте это было бы одно и то же |
| 25 | +alert( map.get(1) ); // 'num1' |
| 26 | +alert( map.get('1') ); // 'str1' |
| 27 | +``` |
| 28 | + |
| 29 | +Как видно из примера выше, для сохранения и чтения значений используются методы `get` и `set`, причём `set` можно чейнить. |
| 30 | + |
| 31 | +**При создании `Map` можно сразу инициализовать списком значений.** |
| 32 | + |
| 33 | +Объект `map` с тремя ключами, как и в примере выше: |
| 34 | + |
| 35 | +```js |
| 36 | +let map = new Map([ |
| 37 | + ['1', 'str1'], |
| 38 | + [1, 'num1'], |
| 39 | + [true, 'bool1'] |
| 40 | +]); |
| 41 | +``` |
| 42 | + |
| 43 | +Аргументом `new Map` должен быть итерируемый объект (не обязательно именно массив), которые должен возвратить объект с ключами `0`,`1` -- также не обязательно массив. Везде утиная типизация, максимальная гибкость. |
| 44 | + |
| 45 | +**В качестве ключей можно использовать и объекты:** |
| 46 | + |
| 47 | +```js |
| 48 | +//+ run |
| 49 | +'use strict'; |
| 50 | + |
| 51 | +let user = { name: "Вася" }; |
| 52 | + |
| 53 | +let visitsCountMap = new Map(); |
| 54 | + |
| 55 | +*!* |
| 56 | +// объект user является ключом в visitsCountMap |
| 57 | +visitsCountMap.set(user, 123); |
| 58 | +*/!* |
| 59 | + |
| 60 | +alert( visitsCountMap.get(user) ); // 123 |
| 61 | +``` |
| 62 | + |
| 63 | +[smart header="Как map сравнивает ключи"] |
| 64 | +Для проверки значений на эквивалентность используется алгоритм [SameValueZero](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-samevaluezero). Он аналогичен строгому равенству `===`, отличие -- в том, что `NaN` считается равным `NaN`. |
| 65 | +[/smart] |
| 66 | + |
| 67 | +Для удаления записей используется метод: |
| 68 | +<ul> |
| 69 | +<li>`map.delete(key)` -- возвращает `true`, если ключ существовал, иначе `false`.</li> |
| 70 | +</ul> |
| 71 | + |
| 72 | +Для проверки существования ключа: |
| 73 | + |
| 74 | +<ul> |
| 75 | +<li>`map.has(key)` -- возвращает `true`, если ключ есть, иначе `false`.</li> |
| 76 | +</ul> |
| 77 | + |
| 78 | +Ещё раз заметим, что используемый алгоритм сравнения ключей аналогичен `===`, за исключением `NaN`, которое равно самому себе: |
| 79 | + |
| 80 | +```js |
| 81 | +//+ run |
| 82 | +'use strict'; |
| 83 | + |
| 84 | +let map = new Map([ [NaN: 1] ]); |
| 85 | + |
| 86 | +alert( map.has(NaN) ); // true |
| 87 | +alert( map.get(NaN) ); // 1 |
| 88 | +alert( map.delete(NaN) ); // true |
| 89 | +``` |
| 90 | + |
| 91 | +### Итерация |
| 92 | + |
| 93 | +Для итерации используется один из трёх методов: |
| 94 | +<ul> |
| 95 | +<li>`map.keys()` -- возвращает итерируемый объект для ключей,</li> |
| 96 | +<li>`map.values()` -- возвращает итерируемый объект для значений,</li> |
| 97 | +<li>`map.entries()` -- возвращает итерируемый объект для записей `[ключ, значение]`, он используется по умолчанию в `for..of`.</li> |
| 98 | +</ul> |
| 99 | + |
| 100 | +Например: |
| 101 | + |
| 102 | +```js |
| 103 | +//+ run |
| 104 | +'use strict'; |
| 105 | + |
| 106 | +let recipeMap = new Map([ |
| 107 | + ['огурцов', '500 гр'], |
| 108 | + ['помидоров', '350 гр'], |
| 109 | + ['сметаны', '50 гр'] |
| 110 | +]); |
| 111 | + |
| 112 | +for(let fruit of recipeMap.keys()) { |
| 113 | + alert(fruit); // огурцов, помидоров, сметаны |
| 114 | +} |
| 115 | + |
| 116 | +for(let amount of recipeMap.values()) { |
| 117 | + alert(amount); // 500 гр, 350 гр, 50 гр |
| 118 | +} |
| 119 | + |
| 120 | +for(let entry of recipeMap) { // то же что и recipeMap.entries() |
| 121 | + alert(entry); // огурцов,500 гр , и т.д., массивы по 2 значения |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +Кроме того, у `Map` есть стандартный методы `forEach`, аналогичный массиву: |
| 126 | + |
| 127 | +```js |
| 128 | +//+ run |
| 129 | +'use strict'; |
| 130 | + |
| 131 | +let recipeMap = new Map([ |
| 132 | + ['огурцов', '500 гр'], |
| 133 | + ['помидоров', '350 гр'], |
| 134 | + ['сметаны', '50 гр'] |
| 135 | +]); |
| 136 | + |
| 137 | +recipeMap.forEach( (value, key, map) => { |
| 138 | + alert(`${key}: ${value}`); // огурцов: 500 гр, и т.д. |
| 139 | +}); |
| 140 | +``` |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | + |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | +Есть и другие методы: |
| 150 | + |
| 151 | +<ul> |
| 152 | +<li>`map.size()` -- количество записей в |
| 153 | + |
| 154 | + |
| 155 | +ToDo |
| 156 | + |
0 commit comments