Rest-параметры и spread при вызове
Три точки ... — самый многозначный оператор в JavaScript. В зависимости от того, где он стоит, он делает прямо противоположные вещи: rest собирает аргументы в массив, а spread разворачивает массив в аргументы.
🤔 Проблема: как принять любое количество аргументов?
Представьте: вам нужна функция, которая складывает числа. Но сколько чисел — неизвестно заранее. Иногда два, иногда пять, иногда десять.
// Так не получится — не знаем сколько параметров нужно
function sum(a, b) { return a + b; } // только 2
function sum(a, b, c) { return a + b + c; } // только 3
function sum(a, b, c, d) { ... } // только 4
До ES6 разработчики использовали специальный объект arguments, который автоматически доступен внутри любой функции. Но это было неудобно — arguments не настоящий массив, и с ним нельзя использовать методы массивов.
// Старый способ (до ES6) — работает, но неудобно
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
// arguments — псевдомассив, нельзя использовать forEach, map и т.д.
ES6 решил эту проблему элегантно — через rest-параметры.
📦 Rest-параметры: собираем аргументы в массив
Rest-параметр обозначается тремя точками перед именем параметра: ...args. Он «собирает» все оставшиеся аргументы в настоящий массив. Слово «rest» по-английски — «остаток», «остальное».
function sum(...numbers) {
// numbers — это настоящий массив!
console.log(numbers); // например: [1, 2, 3, 4, 5]
let total = 0;
for (let num of numbers) {
total += num;
}
return total;
}
console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
console.log(sum()); // 0 (пустой массив)
Раз numbers — это настоящий массив, можно использовать любые методы массивов:
function sum(...numbers) {
// reduce — метод массива, суммирует все элементы
return numbers.reduce((acc, num) => acc + num, 0);
}
// Или через forEach:
function printAll(...items) {
items.forEach((item, index) => {
console.log((index + 1) + ". " + item);
});
}
printAll("яблоко", "банан", "вишня");
// 1. яблоко
// 2. банан
// 3. вишня
✅ Главное отличие от arguments: rest-параметр — настоящий массив, у него есть все методы: forEach, map, filter, reduce и т.д. Объект arguments — псевдомассив без этих методов.
🔀 Rest вместе с обычными параметрами
Rest-параметр можно комбинировать с обычными параметрами. Главное правило: rest-параметр должен быть последним в списке. Логика та же, что и с дефолтами — он собирает «остальное», что не попало в именованные параметры.
// Первые два аргумента — именованные параметры,
// всё остальное — в массиве tags
function createPost(title, author, ...tags) {
console.log("Заголовок:", title);
console.log("Автор:", author);
console.log("Теги:", tags);
}
createPost("Гайд по JS", "Иван", "javascript", "обучение", "начинающим");
// Заголовок: Гайд по JS
// Автор: Иван
// Теги: ["javascript", "обучение", "начинающим"]
createPost("Привет мир", "Мария");
// Заголовок: Привет мир
// Автор: Мария
// Теги: [] — пустой массив, если тегов нет
// ❌ ОШИБКА: rest должен быть последним
function wrong(first, ...rest, last) {
// SyntaxError: Rest parameter must be last formal parameter
}
❌ Помни: rest-параметр — всегда последний. JavaScript не знает, где заканчиваются аргументы для rest и начинаются для last — они поступают по порядку, и «граница» может быть только в конце.
📤 Spread при вызове: разворачиваем массив в аргументы
Те же три точки ... при вызове функции работают наоборот: они разворачивают массив или другую итерируемую структуру в отдельные аргументы. Это называется spread-оператор.
function sum(a, b, c) {
return a + b + c;
}
let numbers = [1, 2, 3];
// Без spread — пришлось бы обращаться по индексам
sum(numbers[0], numbers[1], numbers[2]); // 6 — некрасиво
// Со spread — элегантно!
sum(...numbers); // 6 — числа "высыпаются" из массива как аргументы
Самый частый пример — функции Math.min и Math.max. Они принимают отдельные числа, но не массив. Spread решает эту проблему:
let temperatures = [23, 17, 31, 14, 28, 19];
// Math.max НЕ принимает массив:
Math.max(temperatures); // NaN — не работает!
// Но принимает аргументы через spread:
Math.max(...temperatures); // 31 — правильно!
Math.min(...temperatures); // 14 — правильно!
🔑 Запомните мнемонику:
Rest (...args в параметрах) — собирает в массив
Spread (...arr при вызове) — разворачивает из массива
Три точки — одно и то же, контекст (место) определяет смысл.
🛠️ Больше примеров со spread
Spread используется не только при вызове функций — он очень универсален. Но его применение при вызове — самое важное для понимания темы этого урока.
// Комбинирование массивов через spread:
let fruits = ["яблоко", "банан"];
let vegetables = ["морковь", "лук"];
let food = [...fruits, ...vegetables];
console.log(food); // ["яблоко", "банан", "морковь", "лук"]
// Копирование массива:
let original = [1, 2, 3];
let copy = [...original]; // полная копия, а не ссылка!
copy.push(4);
console.log(original); // [1, 2, 3] — не изменился
console.log(copy); // [1, 2, 3, 4]
// Разворачивание строки в символы:
let letters = [..."привет"];
console.log(letters); // ["п", "р", "и", "в", "е", "т"]
// Практический пример: функция принимает числа, а у нас массив
function calculateAverage(...numbers) {
if (numbers.length === 0) return 0;
let sum = numbers.reduce((acc, n) => acc + n, 0);
return sum / numbers.length;
}
// Вызов с отдельными числами:
calculateAverage(4, 8, 6, 2); // 5
// Есть массив — разворачиваем через spread:
let grades = [4, 8, 6, 2, 10, 7, 5];
calculateAverage(...grades); // 6
⚖️ Rest vs Spread: финальное сравнение
...args)
- Стоит в параметрах при объявлении
- Собирает аргументы в массив
- Всегда последний параметр
- Только один раз в параметрах
- Создаёт настоящий массив
...arr)
- Стоит при вызове функции
- Разворачивает массив в аргументы
- Может быть в любом месте
- Можно использовать несколько раз
- Работает с любым итерируемым объектом
✅ Итоги урока
- До ES6 для переменного числа аргументов использовали
arguments— псевдомассив - Rest-параметр (
...argsв объявлении) — собирает аргументы в настоящий массив - Rest всегда должен быть последним параметром
- Rest можно комбинировать с обычными параметрами — они берут первые аргументы
- Spread-оператор (
...arrпри вызове) — разворачивает массив в отдельные аргументы - Три точки
...— один синтаксис, два смысла: место определяет поведение - Классический пример spread:
Math.max(...arr)для нахождения максимума в массиве
В следующем уроке изучим стрелочные функции — компактный синтаксис ES6, который изменил то, как пишется современный JavaScript. 🚀
Тест: Rest-параметры и spread
6 вопросов