Что такое «параметры покоя»? Зачем нам вообще использовать синтаксис распространения?
Мы начнем с остальных параметров ...
.
Функцию можно вызывать с любым количеством аргументов, независимо от того, как она определена.
Например:
function mult(f, g){ return f * g; } console.log(mult(1, 2, 3, 4, 5, 6))
Не будет ошибки ⛔ из-за «лишних» аргументов. Но, конечно, в результате будут учитываться только первые два.
Остальные параметры можно включить в определение функции, используя три точки ...
, за которыми следует имя массива, который будет их содержать. Точки буквально означают «собрать оставшиеся параметры в массив».
Например, чтобы собрать все аргументы в массив args
:
function multAll(...args) { // args is the name for the array let product = 0; for (let arg of args) product *= arg; return product; } console.log(multAll(1) ); // 1 console.log(multAll(1, 2) ); // 2 console.log(multAll(1, 2, 3) ); // 6
Мы можем получить первые параметры как переменные и собрать только остальные.
Здесь первые два аргумента переходят в переменные, а остальные — в titles
массив:
function showName(firstName, lastName, ...titles) { console.log(firstName + ' ' + lastName); // Dante Alighieri // The rest go into titles array // i.e. titles = ["Consul", "Imperator"] console.log(titles[0] ); // Poet console.log(titles[1] ); // Philosopher console.log(titles.length ); // 2 } showName("Dante", "Alighieri", "Poet", "Philosopher");
Остальные параметры должны быть в конце
Остальные параметры собирают все оставшиеся аргументы, поэтому следующее не имеет смысла и вызывает ошибку:
function g(a, ...rest, b){ // Error }
...rest
всегда должен быть последним.
Далее мы переходим к синтаксису Spread.
Мы только что увидели, как получить массив из списка параметров 📝.
Но иногда нам нужно сделать ровно наоборот.
Например, есть встроенная функция Math.min()
, которая возвращает наименьшее число из списка:
console.log(Math.min(3, 5, 1) ); // 1
Теперь предположим, что у нас есть массив [3, 5, 1]
. Как мы называем Math.min()
с этим?
Передача «как есть» не сработает, потому что Math.min()
ожидает список числовых аргументов, а не один массив:
let arr = [3, 5, 1]; console.log(Math.min(arr) ); // NaN
И, конечно же, мы не можем вручную 🦽 перечислить элементы в коде Math.min(arr[0], arr[1], arr[2])
, потому что мы можем быть не уверены, сколько их. По мере выполнения нашего кода их может быть много, а может и не быть вовсе. И это было бы некрасиво.
Распространяйте синтаксис на помощь! Это похоже на остальные параметры, также использующие ...
, но делает совсем наоборот.
Когда ...arr
используется в вызове функции, он «расширяет» повторяемый объект arr
в списке аргументов.
Для Math.min()
:
let arr = [3, 5, 1]; console.log(Math.min(...arr)); // 1 (Spread turns array into a list of arguments)
Мы также можем передать несколько итераций следующим образом:
let arr1 = [1, -2, 3, 4]; let arr2 = [8, 3, -8, 1]; console.log(Math.min(...arr1, ...arr2) ); // -8
Мы даже можем комбинировать синтаксис распространения с нормальными значениями:
let arr1 = [1, -2, 3, 4]; let arr2 = [8, 3, -18, 1]; console.log(Math.min(1, ...arr1, 2, ...arr2, 25) ); // -18
Кроме того, синтаксис распространения может использоваться для объединения массивов:
let arr = [4, 3, 2]; let arr2 = [5, 8, 25]; let merged = [0, ...arr, 2, ...arr2]; console.log(merged); // 0, 4, 3, 2, 2, 5, 8, 25 (0, then arr, then 2, then arr2)
В приведенных выше примерах мы использовали массив для демонстрации синтаксиса распространения, но подойдет любой итерируемый объект.
Например, здесь мы используем синтаксис расширения, чтобы превратить строку в массив символов:
let str = "Hello"; console.log([...str] ); // 'H', 'e', 'l', 'l', 'o'
Синтаксис расширения использует итераторы для сбора элементов так же, как это делает for...of
.
Итак, для строки for...of
возвращает символы, а ...str
становится 'H', 'e', 'l', 'l', 'o'
. Список символов передается инициализатору массива [...str]
.
Для этой конкретной задачи мы также могли бы использовать Array.from
, потому что он преобразует итерируемый объект (например, строку) в массив:
let str = "Hello"; // Array.from() converts an iterable into an array console.log(Array.from(str) ); // H, e, l, l, o
Результат такой же, как [...str]
.
Но есть тонкая разница между Array.from(obj)
и [...obj]
:
Array.from()
работает как с массивами, так и с итерируемыми объектами.- Синтаксис распространения работает только с итерируемыми объектами.
Таким образом, для задачи преобразования чего-либо в массив Array.from()
имеет тенденцию быть более универсальным.
Заключение
Когда мы видим ...
в коде, это либо остальные параметры, либо синтаксис расширения.
Есть простой способ отличить их 😵:
- Когда
...
находится в конце параметров функции, ее остальные параметры собирают остальную часть списка аргументов в массив. - Когда
...
встречается в вызове функции или подобном, это называется синтаксисом распространения и расширяет массив в список.
Используйте шаблоны 🔭:
- Остальные параметры используются для создания функций, которые принимают любое количество аргументов.
- Синтаксис расширения используется для передачи массива функциям, которым обычно требуется список из множества аргументов.