Set
Об'єкт Set
(множина) дає змогу зберігати унікальні значення будь-якого типу, як примітивні, так і посилання на об'єкти.
Опис
Об'єкти Set
є колекціями значень. Конкретне значення в множині може зустрітись лише раз, воно є неповторним у межах колекції цієї множини. Ітерування елементів Set
відбувається в порядку додання. Порядок додання відповідає порядкові, в якому кожен елемент був успішно вставлений у множину методом add()
(тобто коли до виклику add()
у множині не було ідентичного елемента).
Специфікація вимагає, щоб множини були реалізовані "так, щоб в середньому час доступу був сублінійним відносно числа елементів колекції". Таким чином, внутрішньо вони можуть бути представлені як геш-таблиця (з доступом O(1)), як дерево пошуку (з доступом O(log(N))) або будь-яка інша структура даних, поки складність доступу краща за O(N).
Рівність значень
Рівність значень заснована на алгоритмі SameValueZero. (Раніше використовувався алгоритм SameValue, котрий розглядав 0
і -0
як різні значення. Перевірте сумісність із браузерами.) Це означає, що значення NaN
вважається рівним іншому значенню NaN
(попри те, що NaN !== NaN
), а всі решта значень перевіряються на рівність згідно з семантикою оператора ===
.
Швидкодія
Метод has
перевіряє, чи присутнє значення в множині, використовуючи підхід, що в середньому є швидшим за перевірку більшості елементів, що були до того додані до множини. Для прикладу, це в середньому швидше, ніж метод Array.prototype.includes
, коли масив має length
, що дорівнює значенню size
множини.
Композиція множин
Об'єкт Set
пропонує методи, що дають змогу компонувати множини, як це робиться у математиці. Серед цих методів:
Метод | Тип поверненого значення | Математичний еквівалент | Діаграма Венна |
---|---|---|---|
A.difference(B) |
Set |
||
A.intersection(B) |
Set |
||
A.symmetricDifference(B) |
Set |
||
A.union(B) |
Set |
||
A.isDisjointFrom(B) |
Boolean |
||
A.isSubsetOf(B) |
Boolean |
||
A.isSupersetOf(B) |
Boolean |
Щоб бути більш узагальненими, ці методи приймають не лише об'єкти Set
, але й будь-що, що є множиноподібним.
Множиноподібні об'єкти
Усі методи композиції множин вимагають того, щоб значення this
було справжнім примірником Set
, але їх аргументи повинні бути хоча б множиноподібними. Множиноподібний об'єкт – це об'єкт, що має наступне:
- Властивість
size
, що містить число. - Метод
has()
, який приймає елемент і повертає булеве значення. - Метод
keys()
, який повертає ітератор елементів множини.
Наприклад, об'єкти Map
є множиноподібними, оскільки вони також мають size
, has()
і keys()
, тому вони поводяться неначе множини ключів, коли використовуються у методах множин:
const a = new Set([1, 2, 3]);
const b = new Map([
[1, "один"],
[2, "два"],
[4, "чотири"],
]);
console.log(a.union(b)); // Set(4) {1, 2, 3, 4}
Примітка: Протокол множиноподібності закликає для видачі елементів метод
keys()
, а не[Symbol.iterator]()
. Це зроблено для того, щоб відображення були дієвими множиноподібними об'єктами, адже в випадку відображень ітератор видає записи, проте методhas()
приймає ключі. Масиви не є множиноподібними, тому що не мають методаhas()
і властивостіsize
, а їх методkeys()
видає індекси, а не елементи. Об'єктиWeakSet
також не є множиноподібними, оскільки не мають методаkeys()
.
Set-подібні API браузера
Set
-подібні об'єкти браузера (або "множиноподібні об'єкти") - це інтерфейси API Вебу, що з багатьох боків поводяться подібно до Set
.
Як і в Set
, елементи можуть бути ітеровані в тому ж порядку, в якому вони додані до такого об'єкта.
Також Set
-подібні об'єкти та Set
мають властивості та методи, що поділяють однакові назви та поведінку.
Проте, на відміну від Set
, вони дозволяють лише певний наперед визначений тип для кожного зі своїх елементів.
Дозволені типи задані у визначенні специфікації IDL.
Наприклад, GPUSupportedFeatures
– це Set
-подібний об'єкт, що повинен використовувати рядки як ключі та значення.
Це визначено в специфікації IDL нижче:
interface GPUSupportedFeatures {
readonly setlike<DOMString>;
};
Set
-подібні об'єкти – або доступні лише для зчитування, або також і для запису (дивіться ключове слово readonly
в IDL вище).
Set
-подібні об'єкти лише для зчитування мають властивістьsize
і методи:entries()
,forEach()
,has()
,keys()
,values()
таSymbol.iterator
.- Записні
Set
-подібні об'єкти на додачу мають такі методи:clear()
,delete()
таadd()
.
Ці методи та властивості мають таку ж логіку, як рівносильні аналоги в Set
, окрім обмеження щодо типів елементів.
Нижче – приклади Set
-подібних браузерних об'єктів лише для зчитування:
А це – приклади записних Set
-подібних браузерних об'єктів:
Конструктор
Set()
Створює новий об'єкт
Set
.
Статичні властивості
Set[Symbol.species]
Функція-конструктор, що використовується для створення похідних об'єктів.
Властивості примірника
Ці властивості означені на Set.prototype
і є спільними для всіх примірників Set
.
Set.prototype.constructor
Функція-конструктор, що створила об'єкт-примірник. Для примірників
Set
початковим значенням є конструкторSet
.Set.prototype.size
(розмір)Повертає кількість значень, присутніх в об'єкті
Set
.Set.prototype[Symbol.toStringTag]
Початкове значення властивості
Symbol.toStringTag
– рядок"Set"
. Ця властивість використовується вObject.prototype.toString()
.
Методи примірника
Set.prototype.add()
(додати)Додає новий елемент зі вказаним значенням до об'єкта
Set
, якщо елемента з таким само значенням іще вSet
немає.Set.prototype.clear()
(очистити)Усуває з об'єкта
Set
всі значення.Set.prototype.delete()
(видалити)Усуває елемент, пов'язаний із
value
, та повертає булеве значення, що вказує, чи був елемент успішно усунутий. Після цьогоSet.prototype.has(value)
повернеfalse
.Set.prototype.difference()
Приймає множину та повертає нову множину, що містить елементи, присутні в поточній множині, але відсутні в переданій.
Set.prototype.entries()
(записи)Повертає новий об'єкт-ітератор, що містить масив із
[value, value]
для кожного елемента в об'єктіSet
, у порядку їх додання. Це подібно до об'єктаMap
, якби ключ кожного запису був би водночас власним значенням.Set.prototype.forEach()
(для кожного)Один раз викликає
callbackFn
для кожного значення, присутнього в об'єктіSet
, у порядку їх додання. Якщо наданий параметрthisArg
, то він використовуватиметься при кожному викликуcallbackFn
як значенняthis
.Set.prototype.has()
(має)Повертає булеве значення, що вказує, чи є елемент із даним значенням в об'єкті
Set
.Set.prototype.intersection()
Приймає множину та повертає нову множину, що вміщає елементи, присутні як у поточній множині, так і в переданій.
Set.prototype.isDisjointFrom()
Приймає множину та повертає булеве значення, яке вказує на те, чи відсутні в поточної та переданої множини спільні елементи.
Set.prototype.isSubsetOf()
Приймає множину та повертає булеве значення, яке вказує на те, чи всі елементи поточної множини присутні в переданій.
Set.prototype.isSupersetOf()
Приймає множину та повертає булеве значення, яке вказує на те, чи всі елементи переданої множини присутні в поточній.
Set.prototype.keys()
(ключі)Псевдонім для
Set.prototype.values()
.Set.prototype.symmetricDifference()
Приймає множину та повертає нову множину, що вміщає елементи, присутні в поточній множині або в переданій, але не в них обох.
Set.prototype.union()
Приймає множину та повертає нову множину, що вміщає елементи, присутні в одній з множин або в них обох.
Set.prototype.values()
(значення)Повертає новий об'єкт-ітератор, що видає значення для кожного елемента в об'єкті
Set
, у порядку їх додання.Set.prototype[Symbol.iterator]()
Повертає новий об'єкт-ітератор, що видає значення для кожного елемента в об'єкті
Set
, у порядку їх додання.
Приклади
Використання об'єкта Set
const mySet1 = new Set();
mySet1.add(1); // Set(1) { 1 }
mySet1.add(5); // Set(2) { 1, 5 }
mySet1.add(5); // Set(2) { 1, 5 }
mySet1.add("якийсь текст"); // Set(3) { 1, 5, 'якийсь текст' }
const o = { a: 1, b: 2 };
mySet1.add(o);
mySet1.add({ a: 1, b: 2 }); // o посилається на інший об'єкт, тому це нормально
mySet1.has(1); // true
mySet1.has(3); // false, оскільки 3 не додавали до множини
mySet1.has(5); // true
mySet1.has(Math.sqrt(25)); // true
mySet1.has("Якийсь Текст".toLowerCase()); // true
mySet1.has(o); // true
mySet1.size; // 5
mySet1.delete(5); // усуває 5 з множини
mySet1.has(5); // false, 5 була усунута
mySet1.size; // 4, оскільки одне значення щойно було усунуто
mySet1.add(5); // Set(5) { 1, 'якийсь текст', {...}, {...}, 5 } - видалений раніше елемент буде доданий заново; він не збереже позиції, що мав до видалення
console.log(mySet1); // Set(5) { 1, "якийсь текст", {…}, {…}, 5 }
Ітерування множин
Ітерування множин обходить елементи в порядку їх додавання.
for (const item of mySet1) {
console.log(item);
}
// 1, "якийсь текст", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
for (const item of mySet1.keys()) {
console.log(item);
}
// 1, "якийсь текст", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
for (const item of mySet1.values()) {
console.log(item);
}
// 1, "якийсь текст", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
// тут ключі збігаються зі значеннями
for (const [key, value] of mySet1.entries()) {
console.log(key);
}
// 1, "якийсь текст", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
// За допомогою Array.from перетворює об'єкт Set на об'єкт Array
const myArr = Array.from(mySet1); // [1, "якийсь текст", {"a": 1, "b": 2}, {"a": 1, "b": 2}, 5]
// наступне також запрацює, якщо запустити в контексті документа HTML
mySet1.add(document.body);
mySet1.has(document.querySelector("body")); // true
// перетворення між Set та Array
const mySet2 = new Set([1, 2, 3, 4]);
console.log(mySet2.size); // 4
console.log([...mySet2]); // [1, 2, 3, 4]
// перетин можна імітувати за допомогою
const intersection = new Set([...mySet1].filter((x) => mySet2.has(x)));
// різницю можна імітувати за допомогою
const difference = new Set([...mySet1].filter((x) => !mySet2.has(x)));
// Обійти записи множини за допомогою forEach()
mySet2.forEach((value) => {
console.log(value);
});
// 1
// 2
// 3
// 4
Реалізація базових дій з множинами
// Чи є надмножиною
function isSuperset(set, subset) {
for (const elem of subset) {
if (!set.has(elem)) {
return false;
}
}
return true;
}
// Об'єднання
function union(setA, setB) {
const _union = new Set(setA);
for (const elem of setB) {
_union.add(elem);
}
return _union;
}
// Перетин
function intersection(setA, setB) {
const _intersection = new Set();
for (const elem of setB) {
if (setA.has(elem)) {
_intersection.add(elem);
}
}
return _intersection;
}
// Симетрична різниця
function symmetricDifference(setA, setB) {
const _difference = new Set(setA);
for (const elem of setB) {
if (_difference.has(elem)) {
_difference.delete(elem);
} else {
_difference.add(elem);
}
}
return _difference;
}
// Різниця
function difference(setA, setB) {
const _difference = new Set(setA);
for (const elem of setB) {
_difference.delete(elem);
}
return _difference;
}
// Приклади
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 3]);
const setC = new Set([3, 4, 5, 6]);
isSuperset(setA, setB); // повертає true
union(setA, setC); // повертає Set {1, 2, 3, 4, 5, 6}
intersection(setA, setC); // повертає Set {3, 4}
symmetricDifference(setA, setC); // повертає Set {1, 2, 5, 6}
difference(setA, setC); // повертає Set {1, 2}
Зв'язок з масивами
const myArray = ["value1", "value2", "value3"];
// Використати звичайний конструктор Set, щоб перетворити масив на множину
const mySet = new Set(myArray);
mySet.has("значення1"); // повертає true
// Використати синтаксис розгортання, щоб перетворити множину на масив
console.log([...mySet]); // Покаже точно такий самий масив, як myArray
Усунення дублікатів з масиву
// Використання для усунення дублікатів з масиву
const numbers = [2, 13, 4, 4, 2, 13, 13, 4, 4, 5, 5, 6, 6, 7, 5, 32, 13, 4, 5];
console.log([...new Set(numbers)]); // [2, 13, 4, 5, 6, 7, 32]
Зв'язок із рядками
// Чутливо до регістру (множина буде містити "F" і "f" окремо)
new Set("Firefox"); // Set(7) [ "F", "i", "r", "e", "f", "o", "x" ]
// Пропуск дублікатів ("f" зустрічається в рядку двічі, але множина буде містити лише одне входження)
new Set("firefox"); // Set(6) [ "f", "i", "r", "e", "o", "x" ]
Використання множини для пересвідчення щодо унікальності всіх значень у списку
const array = Array.from(document.querySelectorAll("[id]")).map((e) => e.id);
const set = new Set(array);
console.assert(set.size === array.length);
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Set
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 14 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
@@iterator
|
Chrome Full support 43 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 30 | Safari Full support 9 | WebView Android Full support 43 | Chrome Android Full support 43 | Firefox for Android Full support 36 | Opera Android Full support 30 | Safari on iOS Full support 9 | Samsung Internet Full support 4.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
@@species
|
Chrome Full support 51 | Edge Full support 13 | Firefox Full support 41 | Internet Explorer No support Ні | Opera Full support 38 | Safari Full support 10 | WebView Android Full support 51 | Chrome Android Full support 51 | Firefox for Android Full support 41 | Opera Android Full support 41 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.5.0 |
Set() constructor
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 14 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
new Set(iterable)
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 14 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
Set() without new throws
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 42 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 42 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
new Set(null)
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 37 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 37 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
add
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 | Internet Explorer Partial support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 14 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
clear
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 19 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 19 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
delete
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 14 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
entries
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 24 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 24 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
forEach
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 25 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 25 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
has
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 14 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
Key equality for -0 and 0
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 29 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 29 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 4.0.0 |
size
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 19 | Internet Explorer Full support 11 | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 19 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
values
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 24 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 24 | Opera Android Full support 25 | Safari on iOS Full support 8 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |