Если вы осваиваете JavaScript, то наверняка знаете об операторах rest и spread. Первый группирует несколько значений, второй - разгруппировывает. Но давайте посмотрим чуть глубже.

Привет, Хабр! Меня зовут Александр Дудукало, я автор базового курса по JavaScript. В этом тексте на примерах разберемся, что означает каждый оператор и как использовать их на практике. Подробности под катом!

Что такое rest

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

function sum(a, b) {
 return a + b;
}

console.log(sum(5, 2)); // 7

Она отлично справляется с задачей: на вход принимает два числа и на выходе отдает сумму. Но предположим, что мы хотим сделать так, чтобы функция принимала неограниченное количество чисел. Как это реализовать?

Скорее всего, вы подумаете о массиве:

function sum(numbers) {
 let result = 0;

 for (let i = 0; i < numbers.length; i++) {
   result += numbers[i];
 }

 return result;
}

console.log(sum([3, 5, 4, 1, 2])); // 15

Как видите, функция работает. Но как сделать такую же функцию, которая на входе сможет принимать неограниченное количество аргументов? Смотрим пример:

function sum(...numbers) {
 let result = 0;

 for (let i = 0; i < numbers.length; i++) {
   result += numbers[i];
 }

 return result;
}

console.log(sum(3, 5, 4, 1, 2)); // 15

Rest — это синтаксис в JavaScript, который позволяет собирать неограниченное количество аргументов функции и свойств объекта в массив (или объект). Если проще, то rest берет все, что осталось, и объединяет их. Оператор работает с помощью трех точек «…».

В примере выше ...numbers превращает все переданные аргументы в массив, то есть в параметр собираются все оставшиеся аргументы.

  • Если вызвать sum(1, 2, 3), то внутри функции numbers будет [1, 2, 3].

  • Если вызвать sum(10, 20), то numbers будет [10, 20].

  • Если вызвать без аргументов — [].

А если у функции должны быть и другие параметры, помимо тех, что собираются в массив? Все просто, сначала прописываем параметры, которые не войдут в объединенный массив, а остальные соберет rest:

function welcome(prefix, ...names) {
 for (let name of names) {
   console.log(${prefix}, ${name}!);
 }
}

welcome("Привет", "Андрей", "Оля", "Саша");
Результат в консоли.
Результат в консоли.

Здесь первый prefix становится отдельным параметром, а все остальные аргументы попадают в массив …names.

Бесплатный базовый курс по JS

Рассказываем, как работать с переменными, типами данных, функциями и многом другом!

Начать изучение →

​​Rest с массивами

Rest можно применять не только в функциях, но и в работе с массивами:

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

const [first, second, ...rest] = numbers;

console.log(first);
console.log(second);
console.log(rest);
Пример в консоли.
Пример в консоли.

Здесь rest собрал все остатки массива после первых двух элементов. Кстати, в этом примере также используется деструктуризация — о ней я рассказал в предыдущей статье.

Rest в объектах

С массивами разобрались. Теперь узнаем, можно ли применять rest с объектами. Смотрим пример:

const user = {
 name: "Андрей",
 age: 21,
 city: "Волгоград",
 profession: "разработчик"
};

const { name, ...other } = user;

console.log(name);
console.log(other);

Здесь добавили name в отдельную константу, а все остальное — в объект other. В некоторых случаях, например когда работаете с React, этот прием тоже будет полезным.

Что такое spread

Вы уже знаете, что rest собирает элементы вместе, но есть и обратная операция — разбор элементов с помощью spread. Смотрим пример:

const numbers1 = [1, 2, 3];
const numbers2 = [4, 5];
const combined = [...numbers1, ...numbers2];

console.log(combined);
Пример в консоли.
Пример в консоли.

Все те же три точки, но в другом контексте. Оператор объединяет два массива с помощью одной строки. Конечно, это можно сделать с помощью встроенного метода — об этом расскажу в следующих статьях — или цикла, но посмотрите, как просто и лаконично выглядит код уже сейчас.

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

Если сказать проще, то spread убирает квадратные [] или фигурные {} скобки. Функция позволяет выполнять нужные манипуляции со вложенными элементами. Рассмотрим, как еще можно использовать spread.

Копирование массива

Как просто скопировать элементы массива в другой массив:

const original = [1, 2, 3];
const copy = [...original];

console.log(copy);
console.log(original === copy);
Результат в консоли.
Результат в консоли.

Копирование — это уже отдельная тема для статьи. В этой операции многое зависит от того, что именно вы копируете и чего хотите достичь. Не будем останавливаться на этом. Ниже расскажу о том, что такое мутабельность и ссылки.

Работа с объектами

Объединяем два объекта в один с помощью spread:

const user = { name: "Андрей", age: 25 };
const info = { city: "Волгоград", profession: "разработчик"}
const combined = { ...user, ...info };

console.log(combined);
Результат в консоли. 
Результат в консоли. 

Вышло красиво и просто, согласитесь?

Передача аргументов в функцию

Помните функцию sum из примера в начале статьи. Как быть, если мы захотим передать в нее массив? Сможет ли функция использовать rest и принимать неограниченное количество параметров? На помощь приходит spread:

function sum(...numbers) {
 let result = 0;

 for (let i = 0; i < numbers.length; i++) {
   result += numbers[i];
 }

 return result;
}

const numbers = [1, 3, 5, 7]
console.log(sum(...numbers)); // 16

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

Заключение

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

На этом все, до встречи в следующей статье! Пишите в комментариях, в каких задачах обычно используете rest и spread. 

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