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

Для чего использовал Set?

1.7 Middle🔥 151 комментариев
#JavaScript Core

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Для чего использовал Set?

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

Что такое Set?

Set — это коллекция уникальных значений. Если попытаться добавить дублированное значение, оно не будет добавлено.

// Создание Set
const set1 = new Set();
const set2 = new Set([1, 2, 3, 3, 4, 4]); // дубликаты игнорируются

console.log(set2); // Set(4) { 1, 2, 3, 4 }
console.log(set2.size); // 4

Основные методы Set

const colors = new Set();

// add() - добавить элемент
colors.add('red');
colors.add('blue');
colors.add('red'); // не добавится, уже есть

// has() - проверить наличие
console.log(colors.has('red')); // true
console.log(colors.has('green')); // false

// delete() - удалить элемент
colors.delete('red');
console.log(colors.has('red')); // false

// clear() - очистить
colors.clear();
console.log(colors.size); // 0

// Итерация
colors.add('red');
colors.add('blue');
colors.add('green');

colors.forEach(color => console.log(color)); // red, blue, green

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

Кейс 1: Удаление дубликатов из массива

Это один из самых частых случаев использования Set:

// Проблема: в массиве есть дубликаты
const numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];

// Решение 1: использовать Set
const uniqueNumbers = Array.from(new Set(numbers));
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]

// Решение 2: через spread operator
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3, 4, 5]

// Сравним с другими подходами
// filter + indexOf (медленнее)
const unique2 = numbers.filter((v, i) => numbers.indexOf(v) === i);

// Set работает быстрее благодаря O(1) поиску

Кейс 2: Проверка уникальности элементов

function hasUniqueElements(arr) {
  return arr.length === new Set(arr).size;
}

console.log(hasUniqueElements([1, 2, 3])); // true
console.log(hasUniqueElements([1, 2, 2])); // false

Кейс 3: Пересечение массивов

function intersection(arr1, arr2) {
  const set2 = new Set(arr2);
  return arr1.filter(item => set2.has(item));
}

const array1 = [1, 2, 3, 4, 5];
const array2 = [3, 4, 5, 6, 7];

console.log(intersection(array1, array2)); // [3, 4, 5]

Кейс 4: Разница между двумя массивами

function difference(arr1, arr2) {
  const set2 = new Set(arr2);
  return arr1.filter(item => !set2.has(item));
}

const users1 = ['Иван', 'Петр', 'Мария'];
const users2 = ['Петр', 'Анна'];

console.log(difference(users1, users2)); // ['Иван', 'Мария']

Кейс 5: Отслеживание посещённых узлов (BFS/DFS)

function findPath(graph, start, end) {
  const visited = new Set();
  const queue = [start];
  const parent = new Map();
  
  while (queue.length > 0) {
    const node = queue.shift();
    
    if (node === end) {
      // Восстанавливаем путь
      const path = [];
      let current = end;
      while (current !== undefined) {
        path.unshift(current);
        current = parent.get(current);
      }
      return path;
    }
    
    if (!visited.has(node)) {
      visited.add(node);
      
      for (const neighbor of graph[node]) {
        if (!visited.has(neighbor)) {
          queue.push(neighbor);
          parent.set(neighbor, node);
        }
      }
    }
  }
  
  return null;
}

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

console.log(findPath(graph, 'A', 'F')); // ['A', 'B', 'E', 'F']

Кейс 6: Фильтрация уникальных пользователей в React

import { useState, useMemo } from 'react';

interface User {
  id: number;
  name: string;
  email: string;
}

function UserList({ users }: { users: User[] }) {
  // Получить уникальных пользователей по email
  const uniqueUsers = useMemo(() => {
    const seen = new Set();
    return users.filter(user => {
      if (seen.has(user.email)) {
        return false;
      }
      seen.add(user.email);
      return true;
    });
  }, [users]);
  
  return (
    <ul>
      {uniqueUsers.map(user => (
        <li key={user.id}>{user.name} ({user.email})</li>
      ))}
    </ul>
  );
}

Кейс 7: Сравнение производительности

// Проверка принадлежности элемента

// Массив O(n) при каждой проверке
const arr = [1, 2, 3, 4, 5, 100000];
console.time('Array');
for (let i = 0; i < 100000; i++) {
  arr.includes(99999); // медленно
}
console.timeEnd('Array'); // ~50ms

// Set O(1) при каждой проверке
const set = new Set(arr);
console.time('Set');
for (let i = 0; i < 100000; i++) {
  set.has(99999); // быстро
}
console.timeEnd('Set'); // ~5ms

Кейс 8: Отслеживание активных соединений (WebSocket)

class ConnectionManager {
  #connections = new Set();
  
  addConnection(id) {
    this.#connections.add(id);
    console.log(`Соединение добавлено. Всего: ${this.#connections.size}`);
  }
  
  removeConnection(id) {
    this.#connections.delete(id);
    console.log(`Соединение удалено. Осталось: ${this.#connections.size}`);
  }
  
  hasConnection(id) {
    return this.#connections.has(id);
  }
  
  broadcastMessage(message) {
    for (const connectionId of this.#connections) {
      this.sendToConnection(connectionId, message);
    }
  }
  
  sendToConnection(id, message) {
    console.log(`Отправка ${message} подключению ${id}`);
  }
}

const manager = new ConnectionManager();
manager.addConnection('user1'); // Соединение добавлено. Всего: 1
manager.addConnection('user2'); // Соединение добавлено. Всего: 2
manager.broadcastMessage('Hello!'); // отправит двум пользователям
manager.removeConnection('user1'); // Соединение удалено. Осталось: 1

Кейс 9: Кэширование с ограничением размера

class LRUCache {
  #cache = new Map();
  #maxSize;
  
  constructor(maxSize = 100) {
    this.#maxSize = maxSize;
  }
  
  get(key) {
    if (!this.#cache.has(key)) return undefined;
    
    const value = this.#cache.get(key);
    // Переместить в конец (используется позже)
    this.#cache.delete(key);
    this.#cache.set(key, value);
    return value;
  }
  
  set(key, value) {
    if (this.#cache.has(key)) {
      this.#cache.delete(key);
    } else if (this.#cache.size >= this.#maxSize) {
      // Удалить самый старый (первый элемент)
      const firstKey = this.#cache.keys().next().value;
      this.#cache.delete(firstKey);
    }
    
    this.#cache.set(key, value);
  }
}

const cache = new LRUCache(3);
cache.set('a', 1);
cache.set('b', 2);
cache.set('c', 3);
cache.set('d', 4); // удалит 'a'

Кейс 10: Дебаунсинг с отслеживанием активных операций

class DebounceManager {
  #pending = new Set();
  
  debounce(key, fn, delay = 300) {
    // Отменить предыдущую операцию
    if (this.#pending.has(key)) {
      clearTimeout(this.#pending.get(key));
    }
    
    const timeoutId = setTimeout(() => {
      fn();
      this.#pending.delete(key);
    }, delay);
    
    this.#pending.set(key, timeoutId);
  }
  
  cancelAll() {
    for (const timeoutId of this.#pending.values()) {
      clearTimeout(timeoutId);
    }
    this.#pending.clear();
  }
}

const manager = new DebounceManager();

// Использование при обновлении текста
manager.debounce('search', () => {
  console.log('Поиск выполняется...');
}, 500);

Set vs Map vs Object

СтруктураКогда использоватьПроизводительность
SetУникальные значения, O(1) проверкаОтличная
ArrayУпорядоченные данные, индекс доступХорошая для итерации
MapПары ключ-значение, объекты как ключиОтличная
ObjectПростые структуры данныхХорошая для строк как ключи

Практические советы

// 1. Используй Set для проверки наличия элемента (быстро)
const subscribed = new Set(userIds);
if (subscribed.has(userId)) { /* ... */ }

// 2. Используй Set для деликатных данных (токены, UUID)
const invalidTokens = new Set();
invalidTokens.add(token);

// 3. Используй Set в алгоритмах (граф, поиск в ширину)
const visited = new Set();

// 4. Set может хранить любые значения (не только примитивы)
const objSet = new Set();
objSet.add({ id: 1 });
objSet.add([1, 2, 3]);
objSet.add(function() {});

// 5. Используй WeakSet для объектов, которые могут быть удалены
const observers = new WeakSet();

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

Для чего использовал Set? | PrepBro