Статьи

Подготовка к ECMAScript 6: Set и WeakSet

В одной из моих недавних статей под названием Подготовка к ECMAScript 6: Map и WeakMap я познакомил вас с двумя новыми типами данных, доступными в ECMAScript 6: Map и его слабыми аналогами WeakMap . В этом уроке мы рассмотрим еще один дуэт с похожими типами данных, который называется Set и WeakSet . Они имеют много общего с Map и WeakMap , особенно когда речь идет о доступных методах. Однако, как мы обсудим здесь, они имеют разные области применения.

Как я уже отмечал во всех предыдущих статьях, обсуждающих ECMAScript 6, если вы хотите заполнить то, что мы рассмотрим, вы можете использовать es6-shim Пола Миллера .

Set

Как следует из названия, тип данных Set представляет собой набор элементов (коллекцию). Как предполагает математическое понятие, это означает, что набор позволяет хранить одни и те же элементы только один раз (например, строка «test» не может быть сохранена дважды). Как и другие типы данных JavaScript, не обязательно хранить элементы одного и того же типа, поэтому в одном наборе вы можете хранить массивы, числа, строки и т. Д.

Также стоит отметить, что один элемент в наборе не может быть получен, например, с помощью метода get() . Причина в том, что элемент не имеет ни ключа, ни индекса, к которому вы можете обратиться, чтобы получить его. Но поскольку вы можете убедиться, что элемент содержится в данном экземпляре Set , вам не нужен метод get() . Например, если вы знаете, что строка «test» содержится в наборе, вам не нужно ее извлекать, потому что у вас уже есть это значение. Все еще можно получить все сохраненные элементы, как вы узнаете из этого урока.

«Но когда этот тип данных подходит?», Спросите вы. Ну, скажем, вам нужно хранить идентификаторы некоторых элементов. Когда дело доходит до таких ситуаций, вам не нужны дубликаты. В этих условиях и в ECMAScript 5 большинство из вас, вероятно, использовали массивы или объекты для хранения элементов. Проблема в том, что каждый раз, когда появляется новый элемент, вы должны проверить, что он еще не был добавлен, чтобы избежать дублирования. Если бы вы использовали массив, у вас был бы такой код:

 var collection = [1, 2, 3, 4, 5]; var newElements = [4, 8, 10]; for(var i = 0; i < newElements.length; i++) { if (collection.indexOf(newElements[i]) === -1) { collection.push(newElements[i]); } } 

Используя тип данных Set , вы можете упростить предыдущий код, как показано ниже:

 var collection = new Set([1, 2, 3, 4, 5]); var newElements = [4, 8, 10]; for(var i = 0; i < newElements.length; i++) { collection.add(newElements[i]); } 

Теперь, когда вы знаете, что такое Set и когда его использовать, давайте обсудим свойства и методы.

Set.prototype.size

Свойство size возвращает количество элементов в экземпляре Set . Это похоже на length типа данных Array .

Set.prototype.constructor()

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

 var array = [1, 2, "test", {a: 10}]; var set = new Set(array); 

Set.prototype.add()

Метод add() добавляет новый элемент в набор, если он еще не существует; в противном случае элемент не добавляется. Сигнатура этого метода следующая:

 Set.prototype.add(value) 

где value — это элемент, который вы хотите сохранить. Этот метод изменяет набор, к которому он вызывается, но также возвращает новый набор, позволяя создавать цепочки. Пример использования такой функции показан ниже:

 var set = new Set(); set.add("test").add(1).add({}); 

Этот метод в настоящее время реализован в Firefox, Internet Explorer 11, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 этот метод поддерживается за активацией флага «Включить экспериментальный JavaScript».

Set.prototype.delete()

Таким же образом мы можем добавлять элементы, мы также можем удалять их из набора. Для этого мы можем использовать метод delete() . Он принимает значение для удаления и возвращает true если элемент был успешно удален, или false противном случае. Подпись этого метода показана ниже:

 Set.prototype.delete(value) 

value представляет элемент, который вы хотите удалить.

В настоящее время этот метод реализован в Firefox, Internet Explorer 11, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 необходимо активировать обычный флаг.

Set.prototype.has()

Метод has() является одним из методов, общих для типа данных Set с Map . Это позволяет нам проверить, существует ли элемент в наборе. Возвращает true если значение найдено, или false противном случае. Подпись этого метода заключается в следующем:

 Set.prototype.has(value) 

где value — это значение, которое вы хотите найти.

Этот метод в настоящее время реализован в Firefox, Internet Explorer 11, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 этот метод поддерживается за активацией флага «Включить экспериментальный JavaScript».

Set.prototype.clear()

Метод clear() , аналогичный методу, определенному в Map , — это удобный способ удаления всех элементов из экземпляра Set . У метода нет возвращаемого значения (что означает, что он возвращает undefined ). Подпись clear() показана ниже:

 Set.prototype.clear() 

clear() в настоящее время реализована в Firefox, Internet Explorer 11, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 необходимо активировать обычный флаг.

Set.prototype.forEach()

Другим общим методом с Map является forEach() . Мы можем использовать его для перебора элементов, хранящихся в наборе в порядке вставки. Подпись forEach() выглядит следующим образом:

 Set.prototype.forEach(callback[, thisArg]) 

callback — это функция, запускаемая на каждом из элементов набора. Параметр thisArg используется для установки контекста ( this ) обратного вызова. callback получает три параметра:

  • value : значение обработанного элемента
  • value : значение обработанного элемента
  • set : объект Set обработан

Как видите, обрабатываемое значение передается дважды. Причина в том, чтобы метод forEach() совместимым с forEach() реализованным в Map и Array .

Этот метод поддерживается Firefox, Internet Explorer 11, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 необходимо активировать обычный флаг.

Set.prototype.entries()

Метод entries() позволяет нам получить Iterator для циклического выполнения элементов набора. Iterator содержит массив пар value value для каждого элемента в наборе в порядке вставки. Причина такого дублирования такая же, как и раньше: чтобы он соответствовал методу Map . Сигнатура этого метода:

 Set.prototype.entries() 

Этот метод в настоящее время поддерживается Firefox, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 вам нужно активировать обычный флаг.

Set.prototype.values()

Другим методом, который принадлежит этому типу данных, является values() . Он возвращает объект Iterator содержащий значения элементов набора в порядке вставки. Его подпись следующая:

 Set.prototype.values() 

Этот метод в настоящее время поддерживается Firefox, Chrome 38 и Opera 25. В версиях Chrome до 38 и Opera до 25 этот метод поддерживается после активации флага «Включить экспериментальный JavaScript».

Set.prototype.keys()

Как ни странно, Set также имеет метод keys() . Он выполняет ту же операцию, что и values() , поэтому я не буду описывать это.

WeakSet

WeakSet является слабым аналогом типа данных Set . WeakSet принимает только объекты в качестве своих значений. Это означает, что {} , function(){} (функции наследуются от Object ) и экземпляры ваших собственных классов разрешены, а "test" , 1 и другие примитивные типы данных — нет.

Другое важное отличие состоит в том, что объекты WeakSet не предотвращают сборку мусора, если нет других ссылок на сохраненный объект (ссылка слабая ). Из-за этого различия нет методов для извлечения значений или более чем одного элемента одновременно, таких как Set.prototype.values() и Set.prototype.entries() . Кроме того, как и в WeakMap , недоступно свойство size .

В завершение я хочу подчеркнуть, что Chrome 37 и Opera 24 поддерживают WeakSet и его методы без флага, хотя это не относится к Set . Более новые версии Chrome 38 и Opera 25 по умолчанию поддерживают Set и его методы.

Собираем все вместе

Теперь, когда вы увидели все методы и свойства типов данных Set и WeakSet , пришло время применить их к действию. В этом разделе я разработал две демонстрации, чтобы вы могли поиграть с этими методами и лучше понять их силу. Как вы заметите, я не использовал метод Set.prototype.keys() потому что я думаю, что он хорош только для того, чтобы сбивать с толку разработчиков.

В первой демонстрации я буду использовать объект Set и его методы, кроме Set.prototype.keys() .

  

Демонстрационная версия предыдущего кода показана ниже и также доступна в виде JSFiddle .

Во второй демонстрации мы увидим, как мы можем работать с объектом WeakSet .

  

Демонстрационная версия предыдущего кода показана ниже и также доступна в виде JSFiddle .

Вывод

В этом уроке я рассмотрел новые WeakSet данных Set и WeakSet . В дополнение к Map и WeakMap это самые интересные новые типы, доступные в ECMAScript 6. Надеюсь, вам понравилась статья и вы узнали что-то интересное.