Back to JavaScript
JavaScript
medium
mid

How do you use the spread and rest operators in JavaScript?

Same `...` syntax, opposite jobs. Spread EXPANDS an iterable/object into individual elements (copying arrays/objects, passing args). Rest COLLECTS multiple elements into one array (variadic params, destructuring). Both do shallow copies — nested objects are still shared.

4 min read·~6 min to think through

... is one syntax with two opposite behaviors, and which one it is depends on where it appears.

Spread — expands

Spread takes an iterable/object and spreads it out into individual pieces. It appears in function calls, array literals, object literals:

js
// copy / merge arrays
const copy = [...arr];
const merged = [...a, ...b];

// copy / merge objects (later wins)
const newObj = { ...obj, name: "updated" };

// pass an array as individual arguments
Math.max(...[3, 1, 4]); // Math.max(3, 1, 4)

Rest — collects

Rest takes multiple individual items and gathers them into one array/object. It appears in function parameters and destructuring (always last):

js
// variadic function params
function sum(...nums) {           // nums is a real array
  return nums.reduce((a, n) => a + n, 0);
}

// array destructuring
const [first, ...others] = [1, 2, 3]; // first=1, others=[2,3]

// object destructuring
const { id, ...rest } = user;          // rest = everything except id

The rule of thumb

  • On the right side of =, or inside a call/literalspread (expanding).
  • On the left side (destructuring) or in a parameter listrest (collecting).

The critical caveat: shallow copy

Spread copies one level deep. Nested objects/arrays are still shared by reference:

js
const copy = { ...original };
copy.nested.x = 1; // ❌ also mutates original.nested

For React state and immutable updates this matters — you must spread every level you change, or use structuredClone / a library for deep copies.

Common uses in React

js
setItems([...items, newItem]);             // immutable add
setUser({ ...user, name: "new" });         // immutable update
<Component {...props} />                    // spread props

The framing

"Same ..., opposite jobs. Spread expands — in calls and literals, for copying/merging arrays and objects or passing array args. Rest collects — in parameter lists and destructuring, gathering items into one array. Rule: left side / params = rest, right side / calls / literals = spread. The gotcha that bites people is that spread is a shallow copy — nested references are shared, which is why immutable updates have to spread every level you touch."

Follow-up questions

  • Why is spread only a shallow copy, and when does that bite you?
  • How is rest different from the old `arguments` object?
  • How do you do a deep copy in modern JS?
  • Where can rest appear and where can't it?

Common mistakes

  • Assuming spread does a deep copy — nested objects stay shared.
  • Putting a rest element somewhere other than last.
  • Confusing which one is which because the syntax is identical.
  • Spreading a non-iterable (spread needs an iterable for arrays).

Performance considerations

  • Spread creates a new array/object each time — fine normally, but spreading large arrays repeatedly (e.g. in a reduce) is O(n²). Rest params allocate a real array, unlike the old arguments object.

Edge cases

  • Object spread copies only enumerable own properties (not prototype).
  • Spreading a string spreads it into characters.
  • Rest in destructuring with holes or default values.
  • Order matters in object spread — later keys overwrite earlier.

Real-world examples

  • Immutable state updates in React via {...state} and [...list].
  • Variadic utilities like sum(...nums) and prop forwarding <Comp {...props} />.

Senior engineer discussion

Seniors explain spread vs rest by position, give the left/right rule, and proactively raise the shallow-copy caveat and its impact on immutable updates — plus rest replacing the legacy arguments object.

Related questions