Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How do rest and spread syntax differ in JavaScript?

Quick answer

The same ... notation has two different jobs depending on where it appears. Rest collects remaining values into a single array or object binding; spread expands values into a place that accepts separate arguments, array elements, or object properties. For example, function f(...items) collects arguments, while [...items] expands an iterable into a new array. Read the surrounding syntax to tell which operation is happening. [S1] [S2] [S3]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I keep seeing ... in JavaScript, and I can’t tell whether it gathers values or unpacks them. What’s the practical difference?

Geez

Think of the direction of the operation: rest gathers; spread expands. In a function parameter list, rest puts the arguments left over after named parameters into one array. In an array literal or a function call, spread supplies iterable values as separate elements or arguments. [S1] [S3]

function collect(first, ...rest) {
  return [first, rest];
}

collect("a", "b", "c");
// ["a", ["b", "c"]]

const letters = ["b", "c"];
["a", ...letters];
// ["a", "b", "c"]

The first ... is in a parameter list, so it collects. The second is inside an array literal, so it expands.

Follow-up question

Could you show the difference specifically with a function call? I want to understand what gets passed in each direction.

Geez

A function’s rest parameter gathers arguments as the function receives them. Spread in a call does the reverse: it takes an iterable and supplies its items as individual arguments. [S1] [S3]

function describe(first, ...others) {
  return { first, others };
}

const names = ["Mina", "Omar", "Lee"];

const gathered = describe("Mina", "Omar", "Lee");
// { first: "Mina", others: ["Omar", "Lee"] }

const expanded = describe(...names);
// { first: "Mina", others: ["Omar", "Lee"] }

Here, ...names expands the array for the call. Once the call begins, ...others gathers the arguments after first. The similar-looking syntax is doing opposite jobs at two different points. A function’s rest parameter must be last in its parameter list. [S1]

Follow-up question

Does the same distinction apply to arrays and objects? I’ve seen both destructuring and copying examples.

Geez

Yes. In array destructuring, rest collects the items not already matched; in an array literal, spread inserts iterable items into the new array. [S2] [S3]

const [first, ...remaining] = [10, 20, 30];
// first: 10
// remaining: [20, 30]

const copied = [...remaining];
// [20, 30]

Object syntax works similarly, but note which context you are in:

const { id, ...details } = { id: 7, name: "Kai", active: true };
// details: { name: "Kai", active: true }

const combined = { ...details, label: "Member" };
// { name: "Kai", active: true, label: "Member" }

Object destructuring rest collects enumerable own properties not picked off in the pattern; object-literal spread adds the source’s own properties to a new object. [S2] [S3] These array and object copies are shallow, not deep: nested objects are not recursively copied. [S3]

Follow-up question

What quick check can I use when reviewing code, and are there any cases where I shouldn’t treat the two forms as interchangeable?

Geez

Ask what the surrounding syntax expects. A binding pattern or function parameter is a collection context: rest gathers remaining values, and rest must be last in that parameter list or pattern. [S1] [S2] A function call or array literal is an expansion context for iterable items; an object literal spreads own properties. [S3]

That context matters: a plain object without an iterator cannot be spread into an array literal or function argument list, although object-literal spread uses the object’s properties. [S3] The examples explain syntax and immediate results; they do not establish how your particular application handles values beyond the shown code.

A reusable review routine:

  1. Locate the ... and identify whether it is in a parameter list, destructuring pattern, call, array literal, or object literal.
  2. If it is in a parameter or destructuring pattern, name what is left over; expect rest to collect it. [S1] [S2]
  3. If it is in a call, array literal, or object literal, name what destination receives the expanded items or properties. [S3]
  4. Check whether the source is suitable for that context: iterable for call or array spread, or a source with own properties for object spread. [S3]
  5. If copying, check whether a shallow copy is sufficient for your intended use. [S3]

In short: read the destination, then decide whether ... is gathering into it or expanding values into it.

A practical checklist

  • Identify the exact syntax context containing ....

  • For a parameter or destructuring pattern, list what is explicitly matched and what remains to collect. [S1] [S2]

  • For a call or array literal, confirm the source can provide iterable items. [S3]

  • For object-literal spread, check which source properties are being added. [S3]

  • Treat spread copies as shallow when considering nested values. [S3]

A few more useful answers

Can I put a function rest parameter before another parameter?

No. A rest parameter must be last in the function’s parameter list. [S1]

Can I use an ordinary object with spread in an array literal?

Not unless it is iterable: array-literal and call spread use iterable items. Object-literal spread instead enumerates the source’s own properties. [S3]

Does `[...items]` make a deep copy?

No. Array and object copies made with spread are shallow; nested values are not recursively copied. [S3]

Sources

References used for this guide.

  1. [S1] Rest parameters - JavaScript | MDN
    developer.mozilla.org · Checked
  2. [S2] Destructuring - JavaScript | MDN
    developer.mozilla.org · Checked
  3. [S3] Spread syntax (...) - JavaScript | MDN
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work