Rest-параметры и spread-синтаксис в JavaScript
Rest-параметры собирают аргументы в array, spread-синтаксис разворачивает итерируемые объекты. Узнайте, как использовать оба в JavaScript ES6.
В JavaScript токен из трёх точек ... выполняет две противоположные функции в зависимости от места его написания. Как параметр функции он собирает множество аргументов в один array — это rest-параметр. Везде в остальных местах он разворачивает итерируемый объект или object в отдельные элементы — это spread-синтаксис. Один и тот же символ, зеркальное значение.
Оба были введены в ES6 (2015). На этой странице рассматриваются rest-параметры (включая правило о том, что они должны стоять последними), spread в вызовах функций, в литералах array и object, способы копирования и слияния с помощью spread, различия между rest и spread, а также преимущества обоих перед старым объектом arguments.
Понимание rest-параметров в JavaScript
Rest-параметр позволяет функции принимать неограниченное количество аргументов и получать их в виде настоящего array. Вы пишете ... с именем; это имя становится array, содержащим каждый аргумент, который не был сопоставлен с предыдущим параметром.
Синтаксис и использование
В примере ниже numbers — обычный array, поэтому вы можете вызывать методы array, такие как reduce, прямо на нём — никакого преобразования не нужно.
Rest-параметр должен быть последним
Функция может иметь только один rest-параметр, и он должен быть последним в списке параметров. Именованные параметры перед ним заполняются первыми; rest-параметр затем захватывает всё оставшееся. Размещение его в любом другом месте вызовет SyntaxError.
Преимущества перед объектом arguments
До ES6 единственным способом прочитать все аргументы был специальный объект arguments, доступный внутри не-стрелочных функций. Rest-параметры лучше практически во всём:
- Настоящий array.
argumentsпохож на array (у него естьlengthи индексы), но ему не хватаетmap,filter,reduceи т.д. Rest-параметр — это настоящий array. - Явный и читаемый. Сигнатура
function sum(...numbers)говорит читателю, что функция принимает переменный список.argumentsневидим в сигнатуре. - Можно именовать только дополнительные аргументы. Совмещайте фиксированные параметры с rest-параметром, как показано выше —
argumentsвсегда содержит каждый аргумент, включая те, что уже именованы. - Работает со стрелочными функциями. У стрелочных функций нет собственного объекта
arguments, поэтому rest-параметр — единственный способ собрать переменные аргументы в стрелочной функции.
Погружение в spread-синтаксис
Spread-синтаксис разворачивает итерируемый объект — array, string, Set, Map или любой итерируемый объект — в отдельные элементы везде, где ожидается список значений. Существуют три контекста, где он используется: вызовы функций, литералы array и литералы object.
Spread в литералах array
Внутри [ ] spread вставляет каждый элемент итерируемого объекта в новый array. Это самый чистый способ вставить один array в другой на любой позиции:
Поскольку строки итерируемы, их развёртка даёт array символов:
Spread в вызовах функций
В вызове функции spread превращает array обратно в список отдельных аргументов. Это заменяет старый паттерн func.apply(null, array):
Spread в литералах object
Внутри { } spread копирует собственные перечисляемые свойства object в новый object. При совпадении ключей побеждает более позднее значение — что делает spread идеальным для применения переопределений или значений по умолчанию:
Копирование и слияние
Spread — идиоматический способ создать поверхностную копию или объединить коллекции без изменения оригиналов:
Spread поверхностный. Он копирует только значения верхнего уровня. Вложенные object и array по-прежнему разделяются по ссылке, поэтому изменение вложенного значения влияет на обе копии:
Rest против Spread: как их различить
Токен ... выглядит одинаково в обеих ролях, поэтому используйте позицию, чтобы определить, что вы читаете:
| Rest-параметр | Spread-синтаксис | |
|---|---|---|
| Где встречается | В списке параметров функции | В вызове, литерале array или object |
| Что делает | Собирает множество значений в один array | Разворачивает один итерируемый объект/object во множество значений |
Сторона от = | Левая сторона (цель деструктуризации) | Правая сторона (производимое значение) |
| Пример | function f(...args) {} | f(...args) |
Простой тест: если ...x получает значения — это rest; если производит значения — это spread.
Совместное использование rest-параметров и spread-синтаксиса
Эти два инструмента — зеркальные образы, поэтому они естественно сочетаются: rest собирает аргументы в array на входе, а spread разворачивает array в аргументы на выходе:
Распространённый реальный паттерн — обёртка, которая перенаправляет все аргументы другой функции:
Деструктуризация с паттерном rest
В деструктурирующем присваивании паттерн rest захватывает свойства или элементы, которые не были явно именованы. В object он создаёт object из оставшихся ключей; в array — array из оставшихся элементов.
Заключение
Токен ... — одно из самых полезных дополнений, которые ES6 внёс в JavaScript. Как rest-параметр он собирает переменное количество аргументов в чистый array (и заменяет неудобный объект arguments); как spread-синтаксис он разворачивает итерируемые объекты в вызовы функций, литералы array и object, предоставляя лаконичные поверхностные копии и слияния. Помните два правила, которые чаще всего вводят в заблуждение: rest-параметр должен быть последним параметром, а копии через spread поверхностные.
Связанные темы
- Деструктурирующее присваивание — извлечение значений из array и object, часто используется вместе с паттерном rest.
- JavaScript Array — структура данных, которую rest-параметры передают вам, а spread разворачивает.
- Стрелочные функции — почему стрелочные функции используют rest-параметры вместо
arguments. - Привязка функций — управление
this, часто сочетается со spread при перенаправлении аргументов.