Что такое объект Set в JavaScript и его применение в Node.js?

«Что такое объект Set в JavaScript и его применение в Node.js?» — вопрос из категории JavaScript, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Основные характеристики:

  • Уникальность: Каждое значение может встречаться в Set только один раз. Проверка уникальности использует алгоритм "SameValueZero" (аналогично строгому равенству ===, но где NaN считается равным NaN).
  • Порядок: Элементы перебираются в порядке их добавления.
  • Производительность: Методы add, has, delete работают в среднем за O(1), что делает Set очень эффективным для проверки наличия элемента.

Базовые операции:

const uniqueTags = new Set();

// Добавление
uniqueTags.add('javascript');
uniqueTags.add('nodejs');
uniqueTags.add('javascript'); // Не добавится, дубликат
console.log(uniqueTags); // Set(2) { 'javascript', 'nodejs' }

// Проверка наличия
console.log(uniqueTags.has('nodejs')); // true

// Удаление
uniqueTags.delete('javascript');

// Размер коллекции
console.log(uniqueTags.size); // 1

// Итерация
for (const tag of uniqueTags) {
    console.log(tag); // 'nodejs'
}
// Или преобразование в массив
const tagArray = [...uniqueTags]; // ['nodejs']

Практические примеры использования в Node.js:

  1. Удаление дубликатов из массива — самый частый случай:
    const duplicateIds = [101, 102, 101, 103, 102, 104];
    const uniqueIds = [...new Set(duplicateIds)];
    console.log(uniqueIds); // [101, 102, 103, 104]
  2. Кэширование или отслеживание уже обработанных элементов:

    // При обработке потока данных (например, из WebSocket)
    const processedMessageIds = new Set();
    
    socket.on('message', (message) => {
        if (processedMessageIds.has(message.id)) {
            return; // Уже обрабатывали, игнорируем
        }
        processedMessageIds.add(message.id);
        // ... логика обработки сообщения
    });
  3. Проверка на допустимые значения:

    const validStatuses = new Set(['pending', 'processing', 'shipped', 'delivered']);
    
    function updateOrderStatus(newStatus) {
        if (!validStatuses.has(newStatus)) {
            throw new Error(`Invalid status: ${newStatus}`);
        }
        // ... обновление статуса в БД
    }
  4. Построение отношений (объединение, пересечение, разность):

    const admins = new Set(['user1@mail.com', 'user2@mail.com']);
    const activeUsers = new Set(['user2@mail.com', 'user3@mail.com']);
    
    // Пользователи, которые являются и админами, и активными
    const activeAdmins = new Set([...admins].filter(x => activeUsers.has(x)));
    
    // Все уникальные пользователи из обоих множеств (объединение)
    const allUsers = new Set([...admins, ...activeUsers]);

Отличие от массива: Set не имеет индексов и методов типа map или filter (но его легко преобразовать в массив для этого). Его сила — в гарантированной уникальности и быстром поиске. Отличие от объекта ({}): Set специализирован на хранение коллекции значений, а не пар ключ-значение. Ключами в Set являются сами значения.