Статьи

Коллекции ES6: Использование Map, Set, WeakMap, WeakSet

В этой статье рассматриваются четыре новые коллекции ES6 и предоставляемые ими преимущества.

Большинство основных языков программирования имеют несколько типов сборов данных. Python имеет списки, кортежи и словари. У Java есть списки, наборы, карты, очереди. Руби имеет хэши и массивы. JavaScript до сих пор имел только массивы. Объекты и массивы были рабочими лошадками JavaScript. ES6 представляет четыре новые структуры данных, которые добавят мощности и выразительности языку: Map , Set , WeakSet и WeakMap .

Поиск JavaScript HashMap

HashMaps, словари и хэши — это несколько способов, которыми различные языки программирования хранят пары ключ / значение, и эти структуры данных оптимизированы для быстрого поиска.

В ES5 объекты JavaScript — которые являются просто произвольными наборами свойств с ключами и значениями — могут имитировать хэши, но есть несколько недостатков в использовании объектов в качестве хэшей .

Недостаток № 1: ключи должны быть строками в ES5

Ключи свойств объекта JavaScript должны быть строками, что ограничивает их способность служить набором пар ключ / значение различных типов данных. Конечно, вы можете привести / преобразовать другие типы данных в строки, но это добавляет дополнительную работу.

Недостаток № 2: объекты не являются итеративными по своей природе

Объекты не были предназначены для использования в качестве коллекций, и в результате не существует эффективного способа определить, сколько свойств имеет объект. (См., Например, Object.keys медленно ). Когда вы перебираете свойства объекта, вы также получаете свойства его прототипа. Вы можете добавить iterable свойство ко всем объектам, но не все объекты предназначены для использования в качестве коллекций. Вы можете использовать цикл forin и метод hasOwnProperty() , но это всего лишь обходной путь. Когда вы перебираете свойства объекта, свойства не обязательно извлекаются в том же порядке, в котором они были вставлены.

Недостаток № 3: проблемы со встроенными методами столкновения

Объекты имеют встроенные методы, такие как constructor , toString и valueOf . Если один из них был добавлен как свойство, это может привести к коллизиям. Вы можете использовать Object.create(null) для создания голого объекта (который не наследуется от object.prototype ), но, опять же, это всего лишь обходной путь.

ES6 включает новые типы данных коллекций, поэтому больше нет необходимости использовать объекты и жить с их недостатками.

Использование коллекций карт ES6

Map — это первая структура данных / коллекция, которую мы рассмотрим. Карты представляют собой наборы ключей и значений любого типа. Легко создавать новые Карты, добавлять / удалять значения, перебирать ключи / значения и эффективно определять их размер. Вот основные методы:

Создание карты и использование общих методов

 const map = new Map(); // Create a new Map map.set('hobby', 'cycling'); // Sets a key value pair const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // New Object const normalfoods = {}; // New Object map.set(normalfoods, foods); // Sets two objects as key value pair for (const [key, value] of map) { console.log(`${key} = ${value}`); // hobby = cycling [object Object] = [object Object] } map.forEach((value, key) => { console.log(`${key} = ${value}`); }, map); // hobby = cycling [object Object] = [object Object] map.clear(); // Clears key value pairs console.log(map.size === 0); // True 

Запустите этот пример на JSBin

Использование коллекции Set

Наборы представляют собой упорядоченные списки значений, которые не содержат дубликатов. Вместо того, чтобы индексироваться, как массивы, доступ к наборам осуществляется с помощью ключей. Наборы уже существуют в Java , Ruby , Python и многих других языках. Одно из различий между наборами ES6 и другими языками состоит в том, что порядок важен в ES6 (не во многих других языках). Вот ключевые методы Set:

 const planetsOrderFromSun = new Set(); planetsOrderFromSun.add('Mercury'); planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // Chainable Method console.log(planetsOrderFromSun.has('Earth')); // True planetsOrderFromSun.delete('Mars'); console.log(planetsOrderFromSun.has('Mars')); // False for (const x of planetsOrderFromSun) { console.log(x); // Same order in as out - Mercury Venus Earth } console.log(planetsOrderFromSun.size); // 3 planetsOrderFromSun.add('Venus'); // Trying to add a duplicate console.log(planetsOrderFromSun.size); // Still 3, Did not add the duplicate planetsOrderFromSun.clear(); console.log(planetsOrderFromSun.size); // 0 

Запустите этот пример на JSBin

Слабые коллекции, память и сборщики мусора

JavaScript Сборка мусора — это форма управления памятью, при которой объекты, на которые больше нет ссылок, автоматически удаляются, а их ресурсы возвращаются.

Ссылки Map и Set на объекты строго сохраняются и не позволяют собирать мусор. Это может дорого обойтись, если карты / наборы ссылаются на большие объекты, которые больше не нужны, такие как элементы DOM, которые уже были удалены из DOM.

Чтобы исправить это, ES6 также представляет две новые слабые коллекции под названием WeakMap и WeakSet . Эти коллекции ES6 являются «слабыми», потому что они позволяют объекты, которые больше не должны быть удалены из памяти.

WeakMap

WeakMap — третья из новых коллекций ES6, которые мы освещаем. WeakMaps похожи на обычные Maps , хотя с меньшим количеством методов и вышеупомянутой разницей в отношении сбора мусора.

 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 

Запустите этот пример на JSBin

Случаи использования

У WeakMaps есть несколько популярных вариантов использования . Их можно использовать для сохранения приватности личных данных объекта, а также для отслеживания узлов / объектов DOM.

Пример использования личных данных

Следующий пример от эксперта JavaScript Николаса С. Закаса :

 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 , но доступ к privateDataWeakMap запрещен без конкретного экземпляра Person .

Случай использования DOM-узлов

Проект Google Polymer использует WeakMaps в части кода под названием 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(); } } 

WeakSet

WeakSets — это WeakSets коллекций, элементы которых можно собирать, когда объекты, на которые они ссылаются, больше не нужны. WeakSets не допускают итерации. Их варианты использования довольно ограничены (на данный момент, по крайней мере). Большинство ранних последователей говорят, что WeakSets можно использовать для пометки объектов без их изменения . 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 

Карта Вещи? Записи против ES6 Коллекции

Карты и наборы — это новые коллекции ES6 пар ключ / значение. Тем не менее, объекты JavaScript все еще могут использоваться как коллекции во многих ситуациях. Нет необходимости переключаться на новые коллекции ES6, если ситуация не требует этого.

У MDN есть хороший список вопросов, чтобы определить, когда использовать объект или набор ключей:

  • Ключи обычно неизвестны до времени выполнения, и вам нужно их динамически искать?
  • Все ли значения имеют одинаковый тип и могут быть взаимозаменяемыми?
  • Вам нужны ключи, которые не являются строками?
  • Пары ключ-значение часто добавляются или удаляются?
  • У вас есть произвольное (легко меняющееся) количество пар ключ-значение?
  • Коллекция повторяется?

Новые коллекции ES6 дают более удобный JavaScript

Коллекции JavaScript ранее были довольно ограничены, но это было исправлено в ES6. Эти новые коллекции ES6 добавят мощности и гибкости языку, а также упростят задачу разработчиков JavaScript, которые их принимают.


Эта статья является частью серии веб-разработки от евангелистов Microsoft и DevelopIntelligence, посвященной практическому изучению JavaScript, проектам с открытым исходным кодом и рекомендациям по взаимодействию, включая браузер Microsoft Edge и новый механизм рендеринга EdgeHTML . DevelopIntelligence предлагает курсы обучения JavaScript и React Training через appendTo , их специализированный блог и сайт курсов.

Мы рекомендуем вам тестировать браузеры и устройства, включая Microsoft Edge — браузер по умолчанию для Windows 10 — с бесплатными инструментами на dev.microsoftedge.com , включая средство отслеживания проблем EdgeHTML , где вы можете сообщать или искать проблемы EdgeHTML, такие как проблемы с сайтом соответствие или соответствие стандартам. Кроме того, посетите блог Edge, чтобы оставаться в курсе событий и получать информацию от разработчиков и экспертов Microsoft.