Пошук уроків, статей та іншого контенту
Навчитеся використовувати Set для унікальних значень, перевірки належності та видалення дублікатів.
SetSet — це вбудована колекція JavaScript, яка зберігає лише унікальні значення.
На відміну від масиву, Set автоматично не додає значення, яке вже міститься в колекції:
const numbers = new Set();
numbers.add(10);
numbers.add(20);
numbers.add(10);
console.log(numbers); // Set(2) { 10, 20 }
console.log(numbers.size); // 2Set може містити значення будь-якого типу:
числа;
рядки;
булеві значення;
об'єкти;
функції;
null;
undefined.
SetПорожній Set створюють за допомогою конструктора:
const users = new Set();У конструктор можна передати будь-який ітерований об'єкт, наприклад масив:
const uniqueNumbers = new Set([1, 2, 2, 3, 3, 3]);
console.log(uniqueNumbers); // Set(3) { 1, 2, 3 }Рядок також є ітерованим об'єктом:
const letters = new Set("banana");
console.log(letters); // Set(3) { 'b', 'a', 'n' }Порядок елементів у Set відповідає порядку їхнього першого додавання.
Для додавання використовується метод add():
const tags = new Set();
tags.add("javascript");
tags.add("web");
tags.add("frontend");
console.log(tags); // Set(3) { 'javascript', 'web', 'frontend' }Метод add() повертає сам Set, тому виклики можна об'єднувати в ланцюжок:
const permissions = new Set()
.add("read")
.add("write")
.add("delete");
console.log(permissions);Якщо додати значення повторно, колекція не зміниться:
const ids = new Set();
ids.add(42);
ids.add(42);
ids.add(42);
console.log(ids.size); // 1Метод has() перевіряє, чи містить Set певне значення. Він повертає true або false.
const roles = new Set(["admin", "editor", "author"]);
console.log(roles.has("admin")); // true
console.log(roles.has("guest")); // falseЦе зручно для перевірок належності:
const allowedStatuses = new Set(["pending", "paid", "cancelled"]);
function isValidStatus(status) {
return allowedStatuses.has(status);
}
console.log(isValidStatus("paid")); // true
console.log(isValidStatus("unknown")); // falseSet особливо корисний, коли потрібно багато разів перевіряти наявність елементів у колекції. Для такої задачі він зазвичай виразніше описує намір, ніж масив із includes().
Властивість size повертає кількість унікальних елементів:
const products = new Set(["book", "pen", "book"]);
console.log(products.size); // 2size — це властивість, а не метод, тому круглі дужки не використовуються:
console.log(products.size); // правильно
// console.log(products.size()); // помилкаМетод delete() видаляє вказане значення та повертає результат операції:
true — елемент було знайдено та видалено;
false — такого елемента не було.
const languages = new Set(["JavaScript", "Python", "Go"]);
console.log(languages.delete("Python")); // true
console.log(languages.delete("Ruby")); // false
console.log(languages); // Set(2) { 'JavaScript', 'Go' }Щоб видалити всі елементи, використовуйте clear():
const cacheKeys = new Set(["user:1", "user:2", "user:3"]);
cacheKeys.clear();
console.log(cacheKeys.size); // 0Set можна перебирати за допомогою for...of:
const colors = new Set(["red", "green", "blue"]);
for (const color of colors) {
console.log(color);
}Також доступні методи values(), keys() і entries().
values()values() повертає ітератор значень:
const numbers = new Set([10, 20, 30]);
for (const number of numbers.values()) {
console.log(number);
}keys()У Set немає окремих ключів, тому keys() повертає ті самі значення:
const statuses = new Set(["new", "processing", "done"]);
console.log([...statuses.keys()]);
console.log([...statuses.values()]);Обидва виклики повернуть однаковий масив:
["new", "processing", "done"]entries()entries() повертає пари, у яких ключ і значення однакові:
const numbers = new Set([1, 2]);
for (const entry of numbers.entries()) {
console.log(entry);
}
// [1, 1]
// [2, 2]Такий формат потрібен переважно для сумісності з іншими колекціями JavaScript, зокрема Map.
Set на масивДля створення масиву з елементів Set можна використати spread-синтаксис:
const uniqueValues = new Set([3, 1, 2]);
const array = [...uniqueValues];
console.log(array); // [3, 1, 2]Також можна використати Array.from():
const uniqueValues = new Set(["a", "b", "c"]);
const array = Array.from(uniqueValues);
console.log(array); // ["a", "b", "c"]Після перетворення можна застосовувати методи масиву:
const numbers = new Set([1, 2, 3, 4]);
const doubled = [...numbers].map((number) => number * 2);
console.log(doubled); // [2, 4, 6, 8]Одна з найпоширеніших задач для Set — отримати масив лише з унікальними значеннями:
const values = [1, 2, 2, 3, 1, 4, 3];
const uniqueValues = [...new Set(values)];
console.log(uniqueValues); // [1, 2, 3, 4]Цей підхід працює і для рядків:
const words = ["js", "html", "js", "css", "html"];
const uniqueWords = [...new Set(words)];
console.log(uniqueWords); // ["js", "html", "css"]Універсальна функція може виглядати так:
function removeDuplicates(items) {
return [...new Set(items)];
}
console.log(removeDuplicates([5, 5, 1, 2, 1]));
console.log(removeDuplicates(["a", "b", "a"]));Set зберігає порядок першої появи елементів, тому результат не є випадково перемішаним.
Set визначає унікальністьДля порівняння значень Set використовує алгоритм, близький до Object.is():
const values = new Set();
values.add(NaN);
values.add(NaN);
console.log(values.size); // 1Усі значення NaN вважаються однаковими.
Значення 0 і -0 також вважаються одним елементом:
const numbers = new Set([0, -0]);
console.log(numbers.size); // 1Для примітивів значення порівнюються за їхнім значенням:
const values = new Set([1, 1, "1"]);
console.log(values.size); // 2Число 1 і рядок "1" — різні значення.
SetОб'єкти порівнюються за посиланням, а не за вмістом:
const firstUser = { id: 1 };
const secondUser = { id: 1 };
const users = new Set([firstUser, secondUser]);
console.log(users.size); // 2Хоча об'єкти мають однакові властивості, це два різні об'єкти в пам'яті.
Якщо додати те саме посилання повторно, дубліката не буде:
const user = { id: 1 };
const users = new Set();
users.add(user);
users.add(user);
console.log(users.size); // 1Тому Set не підходить для автоматичного видалення дублікатів об'єктів за значенням певної властивості.
Якщо потрібно залишити лише одного користувача з кожним id, можна використати окремий Set для ідентифікаторів:
function uniqueUsersById(users) {
const ids = new Set();
return users.filter((user) => {
if (ids.has(user.id)) {
return false;
}
ids.add(user.id);
return true;
});
}
const users = [
{ id: 1, name: "Анна" },
{ id: 2, name: "Олег" },
{ id: 1, name: "Анна оновлена" },
{ id: 3, name: "Марія" }
];
console.log(uniqueUsersById(users));Результатом будуть перші об'єкти з унікальними ідентифікаторами.
Розглянемо функцію, яка аналізує відвідані сторінки користувача:
function analyzeVisitedPages(pages) {
const uniquePages = new Set(pages);
return {
totalVisits: pages.length,
uniquePages: uniquePages.size,
hasSettingsPage: uniquePages.has("/settings"),
pages: [...uniquePages]
};
}
const visits = [
"/",
"/products",
"/products",
"/settings",
"/",
"/about"
];
console.log(analyzeVisitedPages(visits));Функція:
створює Set із відвіданих адрес;
автоматично прибирає дублікати;
рахує кількість унікальних сторінок;
перевіряє наявність сторінки налаштувань;
повертає унікальні адреси у вигляді масиву.
У JavaScript Set зручно використовувати для операцій над множинами. Наприклад, можна реалізувати об'єднання, перетин і різницю.
Об'єднання містить усі унікальні елементи з двох множин:
function union(firstSet, secondSet) {
return new Set([...firstSet, ...secondSet]);
}
const frontend = new Set(["HTML", "CSS", "JavaScript"]);
const backend = new Set(["JavaScript", "Node.js", "SQL"]);
console.log(union(frontend, backend));
// Set(5) { "HTML", "CSS", "JavaScript", "Node.js", "SQL" }Перетин містить лише елементи, присутні в обох множинах:
function intersection(firstSet, secondSet) {
return new Set(
[...firstSet].filter((value) => secondSet.has(value))
);
}
const firstGroup = new Set(["A", "B", "C"]);
const secondGroup = new Set(["B", "C", "D"]);
console.log(intersection(firstGroup, secondGroup));
// Set(2) { "B", "C" }Різниця містить елементи першої множини, яких немає у другій:
function difference(firstSet, secondSet) {
return new Set(
[...firstSet].filter((value) => !secondSet.has(value))
);
}
const allFeatures = new Set(["search", "comments", "export"]);
const enabledFeatures = new Set(["search", "comments"]);
console.log(difference(allFeatures, enabledFeatures));
// Set(1) { "export" }Під час роботи з великими колекціями для таких операцій можна перетворити меншу множину на Set, щоб перевірки has() були ефективними.
Set і масив: що обратиВикористовуйте Set, якщо:
кожне значення має бути унікальним;
часто потрібно перевіряти наявність елемента;
порядок елементів важливий, але індекси не потрібні;
потрібно швидко видалити дублікати.
Використовуйте масив, якщо:
потрібен доступ за індексом;
важливі методи map(), filter(), reduce() без попереднього перетворення;
дублікати мають зберігатися;
потрібна робота з послідовністю елементів як зі списком.
Set не має доступу за індексом:
const colors = new Set(["red", "green", "blue"]);
// Не можна отримати елемент так:
// colors[0]Якщо потрібен елемент за індексом, спочатку перетворіть колекцію на масив:
const colors = new Set(["red", "green", "blue"]);
const colorsArray = [...colors];
console.log(colorsArray[0]); // "red"includes()Для невеликих масивів перевірка через includes() часто цілком достатня:
const roles = ["admin", "editor", "author"];
console.log(roles.includes("editor")); // trueАле якщо колекція концептуально є набором унікальних значень і перевірки виконуються регулярно, Set краще передає структуру даних:
const roles = new Set(["admin", "editor", "author"]);
console.log(roles.has("editor")); // trueВажливо: не слід автоматично замінювати кожен масив на Set. Вибір залежить від операцій, які потрібні програмі.
Set не є масивом і не підтримує звернення за індексом:
const values = new Set([10, 20, 30]);
console.log(values[0]); // undefinedПравильно:
const values = new Set([10, 20, 30]);
console.log([...values][0]); // 10size як методуconst items = new Set(["a", "b"]);
// items.size() — помилка
console.log(items.size); // 2delete() без перевірки результатуdelete() повертає false, якщо елемент не знайдено:
const items = new Set(["a", "b"]);
const wasDeleted = items.delete("c");
if (!wasDeleted) {
console.log("Елемент не знайдено");
}const items = new Set([
{ value: 1 },
{ value: 1 }
]);
console.log(items.size); // 2Для об'єктів потрібно явно визначити критерій унікальності, наприклад id, і зберігати вже використані ідентифікатори в іншому Set.
const item = { status: "new" };
const items = new Set([item]);
item.status = "done";
console.log(items.has(item)); // trueSet зберігає посилання на об'єкт. Зміна властивостей не створює нового об'єкта і не змінює результат has() для цього посилання.
У Set немає власних методів map() і filter():
const numbers = new Set([1, 2, 3]);
// numbers.map(...) — помилкаПеретворіть його на масив:
const numbers = new Set([1, 2, 3]);
const doubled = [...numbers].map((number) => number * 2);
console.log(doubled); // [2, 4, 6]Set зберігає лише унікальні значення.
Створити колекцію можна через new Set() або передавши ітерований об'єкт у конструктор.
add() додає значення та ігнорує дублікати.
has() перевіряє наявність елемента.
delete() видаляє один елемент і повертає результат операції.
clear() очищає всю колекцію.
size повертає кількість елементів.
Set можна перебирати через for...of.
Для перетворення на масив використовують [...set] або Array.from(set).
Конструкція [...new Set(array)] видаляє дублікати з масиву.
Примітиви порівнюються за значенням, а об'єкти — за посиланням.
Для унікальності об'єктів за властивістю потрібно самостійно визначити критерій, наприклад зберігати ідентифікатори в окремому Set.