Rest и spread

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 #

...restarguments
типмассивarray-like объект
стрелочные функцииработаетнет собственного arguments
именованные параметрыда, плюс restтолько по индексу
const sumAll = (...nums) => nums.reduce((a, b) => a + b, 0)
sumAll(10, 20, 5) // 35

Частые ошибки #

  1. Глубокое копирование — spread копирует только первый уровень; вложенные объекты остаются общими.
  2. Rest не последний — синтаксическая ошибка: function f(...a, b) {}.
  3. Spread undefined или неитерируемого — в массивах будет ошибка; в объектах null/undefined просто пропускаются.
  4. Путаница rest и spread — rest только слева от = или в параметрах; spread — в правой части и литералах.
const original = { stats: { views: 10 } }
const copy = { ...original }
copy.stats.views = 99
original.stats.views // 99 — общая вложенная ссылка

Итог #

  • Rest собирает «остаток» в массив: в параметрах функции или при деструктуризации.
  • Spread разворачивает массивы, строки и объекты в отдельные элементы или свойства.
  • Spread удобен для копий, слияния и вызовов с динамическим числом аргументов.
  • Копирование поверхностное — для глубоких структур нужны отдельные стратегии.

См. также #