Spread и rest оператор в JavaScript: разница, примеры и типичные ошибки

Spread и rest оператор в JavaScript: разница, примеры и типичные ошибки

Spread и rest оператор в JavaScript: разница, примеры и типичные ошибки

Если вы ищете spread оператор в JavaScript или пытаетесь понять разницу между spread и rest, главный факт такой: синтаксис один и тот же — ..., но смысл зависит от места использования. Spread «раскрывает» массив или объект, а rest «собирает» оставшиеся значения.

Коротко: spread vs rest

Оператор ... в JavaScript используется в двух ролях:

  • Spread — разворачивает элементы массива, объекта или аргументы функции.
  • Rest — собирает несколько значений в массив или объект.
  • Проще всего запомнить так: если ... стоит «на входе» и собирает остаток — это rest. Если «на выходе» раскрывает данные — это spread.

    Spread оператор для массивов

    Spread часто используют, чтобы скопировать массив, объединить несколько массивов или передать элементы массива как отдельные аргументы.

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

    Это удобнее и читаемее, чем старые варианты с concat или ручным циклом.

    const frontend = ['HTML', 'CSS'];
    const backend = ['Node.js', 'PostgreSQL'];
    
    const stack = [...frontend, 'JavaScript', ...backend];
    console.log(stack);
    // ['HTML', 'CSS', 'JavaScript', 'Node.js', 'PostgreSQL']

    Передача массива в функцию

    Допустим, функция ожидает отдельные аргументы, а у вас есть массив. Spread решает это одной строкой.

    const prices = [120, 450, 80, 900];
    
    console.log(Math.max(...prices)); // 900
    console.log(Math.min(...prices)); // 80

    Без spread пришлось бы использовать менее очевидную запись:

    console.log(Math.max.apply(null, prices));

    Spread оператор для объектов

    Spread можно применять и к объектам. Это популярный способ создать копию объекта или собрать новый объект на основе существующего.

    const user = {
      name: 'Анна',
      age: 25
    };
    
    const userCopy = { ...user };
    console.log(userCopy); // { name: 'Анна', age: 25 }

    Также spread удобно использовать для обновления отдельных свойств:

    const user = {
      name: 'Анна',
      age: 25,
      city: 'Москва'
    };
    
    const updatedUser = {
      ...user,
      age: 26
    };
    
    console.log(updatedUser);
    // { name: 'Анна', age: 26, city: 'Москва' }

    Важный момент: если свойства повторяются, побеждает значение, которое указано позже.

    const result = {
      role: 'user',
      role: 'admin'
    };
    
    console.log(result.role); // 'admin'

    Практический пример: настройки по умолчанию

    Spread часто используют для объединения пользовательских настроек с настройками по умолчанию.

    const defaultSettings = {
      theme: 'light',
      notifications: true,
      language: 'ru'
    };
    
    const userSettings = {
      theme: 'dark'
    };
    
    const finalSettings = {
      ...defaultSettings,
      ...userSettings
    };
    
    console.log(finalSettings);
    // { theme: 'dark', notifications: true, language: 'ru' }

    Такой подход часто встречается в реальных проектах: при настройке компонентов, запросов, форм, фильтров и конфигураций.

    Rest параметры в функциях

    Теперь посмотрим на rest. В параметрах функции ... собирает оставшиеся аргументы в массив.

    function sum(...numbers) {
      let total = 0;
    
      for (const number of numbers) {
        total += number;
      }
    
      return total;
    }
    
    console.log(sum(1, 2, 3)); // 6
    console.log(sum(10, 20, 30, 40)); // 100

    Rest параметр должен быть последним в списке параметров:

    function createUser(name, ...skills) {
      return {
        name,
        skills
      };
    }
    
    console.log(createUser('Игорь', 'JS', 'React', 'Git'));
    // { name: 'Игорь', skills: ['JS', 'React', 'Git'] }

    А вот так делать нельзя:

    // Ошибка: rest параметр должен быть последним
    function badExample(...items, lastItem) {
      // ...
    }

    Rest при деструктуризации массивов

    Rest можно использовать, чтобы взять первый элемент массива, а остальные собрать отдельно.

    const fruits = ['apple', 'banana', 'orange', 'mango'];
    
    const [firstFruit, ...otherFruits] = fruits;
    
    console.log(firstFruit); // 'apple'
    console.log(otherFruits); // ['banana', 'orange', 'mango']

    Rest при деструктуризации объектов

    С объектами принцип похожий: можно извлечь нужные свойства, а остальные собрать в новый объект.

    const product = {
      id: 101,
      title: 'Клавиатура',
      price: 3500,
      inStock: true
    };
    
    const { id, ...productInfo } = product;
    
    console.log(id); // 101
    console.log(productInfo);
    // { title: 'Клавиатура', price: 3500, inStock: true }

    Это полезно, когда нужно исключить часть данных перед отправкой на сервер или отображением в интерфейсе.

    Важная ошибка: spread делает поверхностную копию

    Многие новички думают, что { ...object } полностью копирует объект. На самом деле создаётся только поверхностная копия. Вложенные объекты остаются связанными.

    const user = {
      name: 'Олег',
      address: {
        city: 'Казань'
      }
    };
    
    const copy = { ...user };
    copy.address.city = 'Самара';
    
    console.log(user.address.city); // 'Самара'

    Если нужно безопасно копировать вложенные структуры, используйте специальные способы глубокого копирования, например structuredClone, если он подходит для ваших данных.

    const safeCopy = structuredClone(user);
    safeCopy.address.city = 'Уфа';
    
    console.log(user.address.city); // 'Самара'
    console.log(safeCopy.address.city); // 'Уфа'

    Когда использовать spread и rest

  • Используйте spread, когда нужно скопировать массив или объект.
  • Используйте spread, чтобы объединить массивы или объекты.
  • Используйте spread, чтобы передать массив как список аргументов.
  • Используйте rest, когда функция принимает произвольное количество аргументов.
  • Используйте rest, чтобы отделить часть данных при деструктуризации.
  • Советы и лучшие практики

    Несколько рекомендаций, которые помогут писать чище:

  • Не путайте копирование через spread с глубоким копированием.
  • При объединении объектов следите за порядком: последние свойства перезаписывают предыдущие.
  • Не используйте spread для огромных массивов в функциях вроде Math.max(...items): можно упереться в лимит аргументов.
  • Для читаемости называйте rest-переменные во множественном числе: ...items, ...users, ...args.
  • Если вы хотите не просто запомнить отдельные операторы, а уверенно собрать базу JavaScript с практикой, посмотрите курс «JavaScript с Нуля до Гуру 2.0» — понятный путь от основ к уверенной разработке. Он хорошо подойдёт тем, кто хочет системно закрыть пробелы и писать код осознанно.

    Итог

    Spread и rest оператор в JavaScript — это один синтаксис ..., но два разных сценария. Spread раскрывает данные, rest собирает их. Освоив эти приёмы, вы сможете проще работать с массивами, объектами, функциями и деструктуризацией — а код станет короче и понятнее.

    Источник

    НЕТ КОММЕНТАРИЕВ

    Оставить комментарий