Rest и spread #
Rest (...) собирает оставшиеся элементы в массив; spread разворачивает итерируемое значение в отдельные элементы. Один и тот же синтаксис ..., но роль зависит от позиции: в объявлении параметров — rest, в выражении — spread.
Rest-параметры #
Rest заменяет устаревший arguments и всегда даёт настоящий массив:
function logTags(primary, ...extra) {
console.log('главный:', primary)
console.log('остальные:', extra)
}
logTags('javascript', 'замыкания', 'async', 'dom')
// главный: javascript
// остальные: ['замыкания', 'async', 'dom']
Правила:
- rest-параметр только один и только последний в списке;
- до него можно ставить обычные параметры и значения по умолчанию.
function buildSearchUrl(base, page = 1, ...filters) {
const query = filters.map(encodeURIComponent).join(',')
return query ? `${base}?page=${page}&q=${query}` : `${base}?page=${page}`
}
buildSearchUrl('/docs', 2, 'функции', 'замыкания')
// "/docs?page=2&q=%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8,%D0%B7%D0%B0%D0%BC%D1%8B%D0%BA%D0%B0%D0%BD%D0%B8%D1%8F"
Spread в массивах #
Разворачивает элементы при создании массива, передаче аргументов или конкатенации:
const core = ['variables', 'functions']
const advanced = ['closures', 'prototypes']
const roadmap = [...core, 'modules', ...advanced]
roadmap
// ['variables', 'functions', 'modules', 'closures', 'prototypes']
Копия массива (поверхностная):
const scores = [88, 91, 74]
const backup = [...scores]
backup.push(100)
scores // [88, 91, 74] — исходник не изменился
Передача элементов как отдельных аргументов:
const values = [3, 7, 2]
Math.max(...values) // 7
Spread в объектах #
С ES2018 spread работает и с объектами — удобно для неизменяемых обновлений:
const lesson = { id: 12, title: 'Rest и spread', done: false }
const updated = { ...lesson, done: true, reviewedAt: '2026-07-14' }
// { id: 12, title: 'Rest и spread', done: true, reviewedAt: '2026-07-14' }
Поздние свойства перекрывают ранние с тем же ключом:
const defaults = { theme: 'light', fontSize: 16 }
const userPrefs = { theme: 'dark' }
const settings = { ...defaults, ...userPrefs }
// { theme: 'dark', fontSize: 16 }
Rest при деструктуризации #
В присваивании rest собирает «хвост»:
const [first, second, ...rest] = ['a', 'b', 'c', 'd']
first // 'a'
rest // ['c', 'd']
const { title, ...meta } = { title: 'JSFlow', level: 'middle', lang: 'ru' }
meta // { level: 'middle', lang: 'ru' }
Полезно, когда нужно отделить известные поля от остальных перед передачей дальше.
Rest vs arguments #
...rest | arguments | |
|---|---|---|
| тип | массив | array-like объект |
| стрелочные функции | работает | нет собственного arguments |
| именованные параметры | да, плюс rest | только по индексу |
const sumAll = (...nums) => nums.reduce((a, b) => a + b, 0)
sumAll(10, 20, 5) // 35
Частые ошибки #
- Глубокое копирование — spread копирует только первый уровень; вложенные объекты остаются общими.
- Rest не последний — синтаксическая ошибка:
function f(...a, b) {}. - Spread
undefinedили неитерируемого — в массивах будет ошибка; в объектахnull/undefinedпросто пропускаются. - Путаница rest и spread — rest только слева от
=или в параметрах; spread — в правой части и литералах.
const original = { stats: { views: 10 } }
const copy = { ...original }
copy.stats.views = 99
original.stats.views // 99 — общая вложенная ссылка
Итог #
- Rest собирает «остаток» в массив: в параметрах функции или при деструктуризации.
- Spread разворачивает массивы, строки и объекты в отдельные элементы или свойства.
- Spread удобен для копий, слияния и вызовов с динамическим числом аргументов.
- Копирование поверхностное — для глубоких структур нужны отдельные стратегии.