← Назад к вопросам

Для чего нужен Set в JavaScript?

1.0 Junior🔥 121 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего нужен Set в JavaScript

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

Основные особенности Set

1. Уникальные значения

Set автоматически исключает дубликаты:

const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];

// Неправильно — массив содержит дубликаты
console.log(numbers.length); // 10

// Правильно — Set содержит только уникальные значения
const uniqueNumbers = new Set(numbers);
console.log(uniqueNumbers.size); // 4

2. Создание и инициализация

// Пустой Set
const emptySet = new Set();

// Set с начальными значениями
const colors = new Set(['red', 'green', 'blue']);
console.log(colors.size); // 3

// Set из строки (строка — это итерируемая коллекция символов)
const chars = new Set('hello');
console.log(chars); // Set { 'h', 'e', 'l', 'o' }

3. Основные методы

const set = new Set();

// add() — добавляет значение
set.add(1);
set.add(2);
set.add(2); // Не добавится, так как 2 уже в Set

console.log(set.size); // 2

// has() — проверяет наличие значения
console.log(set.has(1)); // true
console.log(set.has(3)); // false

// delete() — удаляет значение
set.delete(1);
console.log(set.has(1)); // false

// clear() — удаляет все значения
set.clear();
console.log(set.size); // 0

Сравнение с массивом

const array = [1, 2, 2, 3];
const set = new Set(array);

// Проверка наличия элемента
// Массив O(n) — медленно
console.log(array.includes(2)); // true

// Set O(1) — быстро
console.log(set.has(2)); // true

// Размер
console.log(array.length); // 4
console.log(set.size); // 3

// Дубликаты
array.push(2);
set.add(2); // Не добавится

Практические применения

1. Удаление дубликатов

// Наивный подход с массивом
function removeDuplicatesArray(arr) {
  return arr.filter((item, index) => arr.indexOf(item) === index);
}

// Быстрый подход с Set
function removeDuplicatesSet(arr) {
  return Array.from(new Set(arr));
}

// Или еще компактнее
const removeDuplicates = (arr) => [...new Set(arr)];

const numbers = [1, 2, 2, 3, 3, 3, 4];
console.log(removeDuplicates(numbers)); // [1, 2, 3, 4]

2. Отслеживание посещённых элементов

// Граф: найти все вершины, достижимые из стартовой
function getReachableNodes(graph, start) {
  const visited = new Set();
  const queue = [start];

  while (queue.length > 0) {
    const node = queue.shift();
    
    if (visited.has(node)) continue;
    visited.add(node);

    for (const neighbor of graph[node] || []) {
      if (!visited.has(neighbor)) {
        queue.push(neighbor);
      }
    }
  }

  return visited;
}

const graph = {
  'A': ['B', 'C'],
  'B': ['D'],
  'C': ['E'],
  'D': [],
  'E': []
};

console.log(getReachableNodes(graph, 'A')); // Set { 'A', 'B', 'C', 'D', 'E' }

3. Отслеживание активных пользователей

class ChatRoom {
  constructor() {
    this.activeUsers = new Set();
  }

  userJoins(userId) {
    this.activeUsers.add(userId);
    console.log(`User ${userId} joined. Active users: ${this.activeUsers.size}`);
  }

  userLeaves(userId) {
    this.activeUsers.delete(userId);
    console.log(`User ${userId} left. Active users: ${this.activeUsers.size}`);
  }

  isUserActive(userId) {
    return this.activeUsers.has(userId);
  }

  getActiveUsers() {
    return Array.from(this.activeUsers);
  }
}

const room = new ChatRoom();
room.userJoins('alice');
room.userJoins('bob');
room.userJoins('alice'); // Не добавится второй раз
console.log(room.isUserActive('alice')); // true
console.log(room.getActiveUsers()); // ['alice', 'bob']

4. Проверка наличия элементов в списке

// Фильтрация: оставить только элементы, которые есть в whitelist
const whitelist = new Set(['apple', 'banana', 'orange']);
const fruits = ['apple', 'grape', 'banana', 'kiwi'];

const filtered = fruits.filter(fruit => whitelist.has(fruit));
console.log(filtered); // ['apple', 'banana']

// Наивный подход был бы медленнее
const whitelistArray = ['apple', 'banana', 'orange'];
const filteredSlow = fruits.filter(fruit => whitelistArray.includes(fruit));

5. Нахождение пересечения и объединения

// Пересечение (общие элементы)
function intersection(setA, setB) {
  return new Set([...setA].filter(x => setB.has(x)));
}

// Объединение (все элементы)
function union(setA, setB) {
  return new Set([...setA, ...setB]);
}

// Разность (элементы из A, которых нет в B)
function difference(setA, setB) {
  return new Set([...setA].filter(x => !setB.has(x)));
}

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);

console.log(intersection(set1, set2)); // Set { 3, 4 }
console.log(union(set1, set2)); // Set { 1, 2, 3, 4, 5, 6 }
console.log(difference(set1, set2)); // Set { 1, 2 }

Итерация по Set

const colors = new Set(['red', 'green', 'blue']);

// for...of
for (const color of colors) {
  console.log(color);
}

// forEach
colors.forEach((color, colorAgain, theSet) => {
  console.log(color);
});

// Конвертирование в массив
const colorArray = Array.from(colors);
const colorArray2 = [...colors]; // Спред оператор

Set с объектами

const user1 = { id: 1, name: 'Alice' };
const user2 = { id: 2, name: 'Bob' };
const user3 = { id: 1, name: 'Alice' }; // Другой объект с тем же содержимым

const users = new Set();
users.add(user1);
users.add(user2);
users.add(user3); // Добавится! Это другой объект

console.log(users.size); // 3

// Set проверяет идентичность (===), не равенство
console.log(user1 === user3); // false
console.log(users.has(user1)); // true
console.log(users.has(user3)); // false

Производительность

// Измерение производительности
const largeArray = Array.from({ length: 100000 }, (_, i) => i);
const duplicateArray = [...largeArray, ...largeArray];

// Массив: медленно O(n²) для filter + indexOf
console.time('array');
const unique1 = duplicateArray.filter(
  (item, index) => duplicateArray.indexOf(item) === index
);
console.timeEnd('array'); // ~1000ms

// Set: быстро O(n)
console.time('set');
const unique2 = Array.from(new Set(duplicateArray));
console.timeEnd('set'); // ~5ms

WeakSet

Для объектов можно использовать WeakSet — это аналог Set, но со слабыми ссылками (garbage collection):

const wset = new WeakSet();
let obj = { id: 1 };

wset.add(obj);
console.log(wset.has(obj)); // true

obj = null; // Объект удаляется из памяти и автоматически из WeakSet

Итоги

  • Set хранит уникальные значения и автоматически исключает дубликаты
  • has() работает за O(1) — намного быстрее, чем includes() в массиве
  • Идеален для удаления дубликатов, отслеживания состояния, проверки наличия
  • Сложнее с объектами — проверяет идентичность, а не равенство
  • WeakSet для объектов с автоматической очисткой при garbage collection