What are the spread and rest operators in JavaScript?

Both use ... but do opposite things: spread expands an iterable into individual elements; rest collects multiple elements into an array.

JavaScript

Overview

The three-dot `...` syntax serves two complementary purposes depending on where it appears: **spread** expands an array or object into individual elements (unpacking); **rest** collects remaining elements into a new array or object (packing).

Key Points

  • •Spread in a call: `fn(...arr)` passes array elements as arguments.
  • •Spread in a literal: `[...arr]` or `{...obj}` creates a shallow copy.
  • •Object spread merges objects: `{ ...defaults, ...overrides }` - later keys win.
  • •Rest in params: `function fn(a, b, ...rest)` collects extra arguments.
  • •Rest in destructuring: `const [first, ...others] = arr` collects remaining.
  • •Both only do a **shallow** copy of objects and arrays.

Examples

Spread: copy and merge arrays

javascript
const a = [1, 2, 3];
const b = [4, 5, 6];

const combined = [...a, ...b];      // [1, 2, 3, 4, 5, 6]
const copy     = [...a];            // [1, 2, 3] (shallow copy)
const withItem = [0, ...a, 99];     // [0, 1, 2, 3, 99]

Spread: merge objects (last key wins)

javascript
const defaults = { theme: 'light', lang: 'en', fontSize: 14 };
const userPrefs = { theme: 'dark', fontSize: 18 };

const config = { ...defaults, ...userPrefs };
// { theme: 'dark', lang: 'en', fontSize: 18 }
// userPrefs.theme overrides defaults.theme

Spread: pass array as function arguments

javascript
const numbers = [3, 1, 4, 1, 5, 9];

Math.max(...numbers);       // 9 - spread as individual args
Math.max.apply(null, numbers); // old way to do the same

Rest: collect extra function arguments

javascript
function sum(first, ...rest) {
  return rest.reduce((acc, n) => acc + n, first);
}

sum(1, 2, 3, 4); // 10 - first=1, rest=[2,3,4]

Rest: destructuring remainder

javascript
const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]

const { id, ...rest } = { id: 1, name: 'Alice', role: 'admin' };
console.log(id);   // 1
console.log(rest); // { name: 'Alice', role: 'admin' }

Pro Tip

Object spread `{ ...obj }` is the cleanest way to immutably update an object: `const updated = { ...user, name: "Bob" }`. This is the pattern used in React state updates and Redux reducers to avoid mutating the original.