В этой статье мы познакомимся с новыми коллекциями в JavaScript:
Все они были введены в спецификацию JavaScript с ES2015, также известным как ES6.
И все они являются итерируемыми структурами. Так же, как String и Array. Это означает, что мы можем использовать for… of для итерации по этим коллекциям и получения доступа к каждому из их элементов.
Set это набор уникальных значений, которые могут быть любого типа. Это буквально означает, что вы можете поместить любое значение в Set, и да, вы можете смешивать типы внутри набора, как в обычных массивах JavaScript. Эта коллекция похожа на HashSet в мире C#, Set/HashSet в Java и Set в Python.
Синтаксис:
new Set([iterable]);
iterable — какой нибудь итерируемый объект. Проще говоря «итерируемый» — это то, что мы можем перебирать, и обычно это последовательность или набор элементов.
Давайте посмотрим на пример с Set:
let set = new Set([3, 5, true, 'This is a string, obviously.']); for (let item of set.values()) { console.log(item); } /* Вывод: 3 5 true This is a string, obviously. */
Поскольку сам Set является итеративным, мы можем использовать оператор for..of :
let set = new Set([3, 5, true, 'This is a string, obviously.']); for (let item of set) { console.log(item); } /* Вывод: 3 5 true This is a string, obviously. */
Как мы уже говорили, значения внутри Set уникальны. Если мы попытаемся добавить значение, которое уже существует в наборе, оно будет просто проигнорировано:
let set = new Set([3, 5, true, 'This is a string, obviously.']); for (let item of set.values()) { console.log(item); } console.log('Adding a new value'); set.add(5); for (let item of set.values()) { console.log(item); }
Set имеет очень полезное свойство под названием size, которое дает нам информацию о количестве значений внутри коллекции.
Наиболее важные методы, присутствующие в экземпляре Set:
Синтаксис:
mySetInstance.forEach(function callback(value1, value2, Set) { // some code that will be run for every value inside ofSet }[, thisArg])
Если вы знакомы с синтаксисом forEach для Array, вы заметите, что он имеет такую же подпись. За исключением того, что с массивом у нас есть индекс в качестве второго аргумента.
Для записи Map также использует тот же синтаксис, однако второй аргумент является ключем.
Поскольку Set не имеет ключей или индексов, его вторым аргументом обратного вызова является значение.Такой же синтаксис для обратного вызова Set был сделан для того, чтобы эти коллекции имели одинаковый синтаксис.
Первые два аргумента обратного вызова value1 и value2 буквально одинаковы и представляют значение внутри Set.
Третий аргумент представляет объект Set.
Мы можем просто преобразовать Set в Array, используя деструктуризацию:
let set = new Set([9, 15]); set.add(44); let arr = [...set]; console.log(arr); // [9, 15, 44]
Как мы уже говорили, Set — это коллекция, которая имеет уникальные значения, то есть не может иметь дубликатов. Мы только что увидели, как мы можем получить Array из Set, рассмотрим как мы можем с помощью Set получить массив уникальных элементов из Array (или из любого итеративного объекта).
Пример:
let arr = [ 13, 11, 15, 21, 13, 11, 17, 17, 19, 19, 21 ]; let uniqueArray = [...new Set(arr)]; console.log(uniqueArray); // [13, 11, 15, 21, 17, 19]
Это удобно, и это, безусловно, может пригодиться для фильтрации массивов и получения уникальных значений.
Map в основном представляет собой набор пар ключ/значение. Это похоже на Dictionary в C#, Map в Java, Hash в Ruby и Dictionary в Python.
Map также имеет свойство под названием size, которое дает нам информацию о количестве ключей/значений внутри коллекции.
Следующие методы присутствуют в экземпляре Map:
Вот пример создания нового объекта Map:
let map = new Map([['name', 'CodingBlast'], ['points', 33], [true, 55], ['true', 44]]) for (let [key, value] of map.entries()) { console.log('key is ' + key + ', value is ' + value); } /* Вывод: key is name, value is CodingBlast key is points, value is 33 key is true, value is 55 key is true, value is 44 */
Мы также можем просмотреть список ключей или значений:
for (let key of map.keys()) { console.log('key:' + key); } for (let value of map.values()) { console.log('value:' + value); }
Вопрос есть ли способ просто распечатать все ключи или значения данного Map. Да, есть!
Мы можем использовать удобный метод Array.from:
let map = new Map([['name', 'CodingBlast'], ['points', 33], [true, 55], ['true', 44]]) console.log(Array.from(map.keys())) console.log(Array.from(map.values())) console.log(Array.from(map.entries())) /* (4) ["name", "points", true, "true"] (4) ["CodingBlast", 33, 55, 44] (4) [Array(2), Array(2), Array(2), Array(2)] */
Последняя строка console.log просто распечатает тот же массив, который мы указали при создании экземпляра карты. Ну, это массив, который имеет массивы в качестве элементов.
Вы, наверное, задаетесь вопросом, зачем нам использовать Map, если мы можем просто использовать объекты JavaScript. Они очень похожи на Map, и так же состоят из пар ключ/значения. Основные отличия Map от Object:
Кроме того, каждый объект по умолчанию уже имеет несколько ключей, в то время как экземпляр Map по умолчанию не имеет ключей/значений. Давайте посмотрим на пример:
let obj = {}; console.log(obj['toString']) console.log(obj['hasOwnProperty']) console.log(obj['constructor']) /* ƒ toString() { [native code] } ƒ hasOwnProperty() { [native code] } ƒ Object() { [native code] } */
Но, конечно же, мы можем использовать встроенный метод hasOwnProperty, чтобы проверить, действительно ли ключ находится в объекте или в одном из прототипов. Также мы обычно используем метод Object.keys(), чтобы получить только собственные и перечисляемые ключи данного объекта.
Список критериев выбора Map или Object:
1. Object является отличным выбором для сценариев, когда нам нужна простая структура для хранения данных и мы знаем, что все ключи являются либо строками, либо целыми числами (или символами), потому что создание простого объекта и доступ к свойству объекта с определенным ключом намного быстрее, чем создание с Map.
2. Кроме того, в сценариях, где существует необходимость применять отдельную логику к отдельным свойствам/элементам, Object, безусловно, является выбором. Например:
var obj = { id: 1, name: "It's Me!", print: function(){ return `Object Id: ${this.id}, with Name: ${this.name}`; } } console.log(obj.print());//Object Id: 1, with Name: It's Me.
3. Более того, JSON имеет прямую поддержку Object, но не с Map (пока). Поэтому в определенной ситуации, когда нам приходится много работать с JSON, рассмотрите Object как предпочтительный вариант.
4. В противоположность, Map является чисто хеш-функцией, Object — чем-то большим (с поддержкой внутренней логики). А использование оператора delete со свойством Object имеет несколько проблем с производительностью. Следовательно, в сценариях, которые требуют много добавления и удаления (особенно) новой пары, Map может работать намного лучше.
5. Кроме того, Map сохраняет порядок своих ключей — в отличие от Object, и Map был создан с учетом итерации, поэтому в случае, если итерация или порядок элементов очень важны, рассмотрите Map — он обеспечит стабильную производительность итерации во всех браузерах.
6. И, наконец, что не менее важно, Map имеет тенденцию работать лучше при хранении большого набора данных, особенно когда ключи неизвестны до времени выполнения, и когда все ключи имеют одинаковый тип и все значения имеют одинаковый тип.
Сборщик мусора JavaScript — это форма управления памятью, при которой объекты, на которые больше нет ссылок, автоматически удаляются, а их ресурсы возвращаются.
Ссылки на объекты внутри Map и Set всегда сохраняются и не позволяют собирать мусор. Это может дорого обойтись, если Map/Set ссылаются на большие объекты, которые больше не нужны, такие как элементы DOM, которые уже были удалены из DOM.
Чтобы исправить это, ES6 также представляет две новые слабые коллекции под названием WeakMap и WeakSet. Эти коллекции ES6 являются «слабыми», поскольку они допускают удаление объектов из памяти, которые больше не нужны.
WeakMap — третья из новых коллекций ES6, которые мы представляем. WeakMap похожи на обычные Map, хотя с меньшим количеством методов и вышеупомянутой разницей в отношении сбора мусора.
const aboutAuthor = new WeakMap(); // Create New WeakMap const currentAge = {}; // key must be an object const currentCity = {}; // keys must be an object aboutAuthor.set(currentAge, 30); // Set Key Values aboutAuthor.set(currentCity, 'Denver'); // Key Values can be of different data types console.log(aboutAuthor.has(currentCity)); // Test if WeakMap has a key aboutAuthor.delete(currentAge); // Delete a key
У WeakMap есть несколько популярных вариантов использования. Их можно использовать для обеспечения конфиденциальности личных данных объекта, а также для отслеживания узлов / объектов DOM.
Пример использования c личными данными
var Person = (function() { var privateData = new WeakMap(); function Person(name) { privateData.set(this, { name: name }); } Person.prototype.getName = function() { return privateData.get(this).name; }; return Person; }());
Использование WeakMap упрощает процесс сохранения конфиденциальности данных объекта. Можно ссылаться на объект Person, но доступ к privateData WeakMap запрещен без конкретного экземпляра Person.
Случай использования с DOM-узлов
Проект Google Polymer использует WeakMap во фрагменте кода под названием PositionWalker.
PositionWalker отслеживает положение в поддереве DOM в качестве текущего узла и смещение в этом узле.
WeakMap используется для отслеживания изменений, удалений и изменений узла DOM:
_makeClone() { this._containerClone = this.container.cloneNode(true); this._cloneToNodes = new WeakMap(); this._nodesToClones = new WeakMap(); ... let n = this.container; let c = this._containerClone; // find the currentNode's clone while (n !== null) { if (n === this.currentNode) { this._currentNodeClone = c; } this._cloneToNodes.set(c, n); this._nodesToClones.set(n, c); n = iterator.nextNode(); c = cloneIterator.nextNode(); } }
WeakSets
— это наборы коллекций, элементы которых можно собирать, когда объекты, на которые они ссылаются, больше не нужны. WeakSet не допускают итерации. Их варианты использования довольно ограничены (на данный момент, по крайней мере). Большинство ранних последователей говорят, что WeakSet можно использовать для пометки объектов без их изменения. ES6-Features.org содержит пример добавления и удаления элементов из WeakSet для отслеживания того, были ли объекты помечены или нет:
let isMarked = new WeakSet() let attachedData = new WeakMap() export class Node { constructor (id) { this.id = id } mark () { isMarked.add(this) } unmark () { isMarked.delete(this) } marked () { return isMarked.has(this) } set data (data) { attachedData.set(this, data) } get data () { return attachedData.get(this) } } let foo = new Node("foo") JSON.stringify(foo) === '{"id":"foo"}' foo.mark() foo.data = "bar" foo.data === "bar" JSON.stringify(foo) === '{"id":"foo"}' isMarked.has(foo) === true attachedData.has(foo) === true foo = null /* remove only reference to foo */attachedData.has(foo) === false isMarked.has(foo) === false
В этой статье мы рассмотрели новые коллекции в JavaScript: Set, Map, WeakMap, WeakSet. Разницу между Set и Map. Что выбрать между Map и Object. А так же для чего можно использовать WeakMap и WeakSet
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
Отличный материал для подготовки к собеседованию. И спасибо за публикацию ссылки на мой блог (в другой статье) ;)
Спасибо за материал, мне помогла инфа, долго искала что-то подобного формата