Курс →React JS

для начинающих
от платформы StackDev.ru

Операторы Spread и Rest в Javascript ES6 (просто и c примерами)

Дата:
Javascript

Spread оператор (оператор расширения) 'берет' каждый отдельный элемент итерируемого объекта (массив) и 'распаковывает' его в другой итерируемый объект (массив).

Что такое итерируемые (перебираемые) объекты?

К итерируемым объектам можно отнести все, что можно перебрать с помощью цикла for..of. Большая часть задач, где приходится использовать оператор spread, касается массивов и строк.

Где и когда используется spread?

Предположим у нас есть 2 массива с сериалами.

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];

В какой-то момент мы решаем создать еще один массив, который будет включать все сериалы из обоих массивов. Как это сделать?

Мы можем использовать метод .concat(), который возвращает новый массив, состоящий из элементов 1-го и 2-го массива.

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4const tvSeries = tvSeriesOne.concat(tvSeriesTwo);
5console.log(tvSeries);
6// [ "Ozark", "Fargo", "Dexter", "Mr. Robot", "Barry", "Suits" ]

Что если мы захотим вставить сериал Sherlock в середину нашего общего списка?

Теоретически, мы также сможем это сделать с помощью метода .concat():

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4let tvSeries = [];
5
6tvSeries = tvSeries.concat(tvSeriesOne);
7tvSeries.push('Sherlock');
8tvSeries = tvSeries.concat(tvSeriesTwo);
9
10console.log(tvSeries);
11// [ "Ozark", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]

Если использовать оператор spread, то наш код будет выглядеть более коротко и понятно.

Так будет выглядеть создание одного общего массива с помощью оператора spread:

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4const tvSeries = [...tvSeriesOne, ...tvSeriesTwo];
5console.log(tvSeries);
6// [ "Ozark", "Fargo", "Dexter", "Mr. Robot", "Barry", "Suits" ]

То есть мы использовали оператор spread, чтобы взять каждый сериал из 1-го и 2-го массива и добавили его в новый массив tvSeries.

Также можно добавить Sherlock в середину общего списка:

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4const tvSeries = [...tvSeriesOne, 'Sherlock', ...tvSeriesTwo];
5console.log(tvSeries);
6// [ "Ozark", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]

Теперь давайте попробуем создать копию нашего массива tvSeries:

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4const tvSeries = [...tvSeriesOne, 'Sherlock', ...tvSeriesTwo];
5const allSeriesList = tvSeries;
6
7console.log(allSeriesList);
8// [ "Ozark", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]

Что если мы решим изменить первый элемент нового массива allSeriesList с 'Ozark' на 'Friends'?

1allSeriesList[0] = 'Friends';

Нам удалось поменять 1-й элемент allSeriesList на 'Friends'. Проблема в том, что мы также изменили наш исходный массив tvSeries.

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4const tvSeries = [...tvSeriesOne, 'Sherlock', ...tvSeriesTwo];
5const allSeriesList = tvSeries;
6
7allSeriesList[0] = 'Friends';
8
9console.log(allSeriesList);
10// [ "Friends", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]
11console.log(tvSeries);
12// [ "Friends", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]

На самом деле мы не создали копию массива. Переменная allSeriesList просто содержит ссылку на наш исходный массив (также как и tvSeries).

1-й способ создать копию массива – использовать метод .concat():

1let allSeriesList = [].conctat(tvSeries);

2-й способ - с помощью оператора spread. Можно создать новый пустой массив и добавить в него каждый элемент исходного массива.

1const tvSeriesOne = ['Ozark', 'Fargo', 'Dexter'];
2const tvSeriesTwo = ['Mr. Robot', 'Barry', 'Suits'];
3
4const tvSeries = [...tvSeriesOne, 'Sherlock', ...tvSeriesTwo];
5
6// Создаем копию
7const allSeriesList = [...tvSeries];
8// Меняем первый элемент новго массива
9allSeriesList[0] = 'Friends';
10
11console.log(tvSeries);
12// [ "Ozark", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]
13console.log(allSeriesList);
14// [ "Friends", "Fargo", "Dexter", "Sherlock", "Mr. Robot", "Barry", "Suits" ]

Таким образом, мы использовали оператор spread, чтобы создать копию массива tvSeries. Наши изменения в новом массиве allSeriesList никак не затронули исходный массив tvSeries.

Оператор Rest

Визуально, оператор rest … (три точки) похож на оператор spread, но выполняет противоположную функцию.

Spread забирает каждый элемент из массива и распаковывает в новый массив. Оператор rest забирает каждый элемент из массива и создает из них новый массив.

Есть 2 типа задач, где оператор rest используется чаще всего – в функциях и в процессе деструктуризации.

Пример 1. Оператор rest в функциях

Предположим, мы продаем пиццу. Стоимость нашей самой популярной пиццы “Маргарита” – 500 Руб.

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

Пример: Стоимость = 500, посетитель A заказал 3 штуки, посетитель B10 штук, посетитель C6 штук, D20 штук.

Мы будем записывать стоимость пиццы в переменную price, а количество пицц в переменную rest (можно назвать как угодно).

1function buyPizza(price, ...rest) {
2 console.log(price); // 500
3 console.log(rest);
4 // Array(4) [ 3, 10, 6, 20 ]
5}
6buyPizza(500, 3, 10, 6, 20);

Таким образом, мы можем подсчитать стоимость заказа для каждого посетителя:

1function buyPizza(price, ...rest) {
2 return rest.map((quantity) => {
3 return price * quantity;
4 });
5}
6buyPizza(500, 3, 10, 6, 20);
7// Array(4) [ 1500, 5000, 3000, 10000 ]

Мы можем добавить еще одну переменную, которая, например, будет подсчитывать стоимость доставки:

1function buyPizza(price, dostavka, ...rest) {
2 console.log(price); // 500
3 console.log(dostavka); // 200
4 return rest.map((quantity) => {
5 return price * quantity;
6 });
7}
8buyPizza(500, 200, 3, 10, 6, 20);
9// Array(4) [ 1500, 5000, 3000, 10000 ]

Пример 2. Оператор rest и деструктуризация

Предположим, у нас есть массив, в котором содержится название пиццы, ее 'ID' в нашей системе заказов и количества заказанной пиццы для разных посетителей:

1const pizza = ['Pepperoni', 2222, 5, 6, 10, 30, 1];

Мы можем получить название пиццы, ее ID и количества и присвоить 3-м новым переменным, используя оператор rest в процессе деструктуризации.

1const pizza = ['Pepperoni', 2222, 5, 6, 10, 30, 1];
2
3const [name, id, ...rest] = pizza;
4console.log(name); // Pepperoni
5console.log(id); // 2222
6console.log(rest);
7// [ 5, 6, 10, 30, 1 ]

Таким образом мы собрали все количества заказанной пиццы и создали из них отдельный новый массив.