Menu

JavaScript Rest and Spread: The ... Operator Explained

How the ... operator works in JavaScript — collecting arguments with rest parameters, expanding arrays and objects with spread, and when to reach for each.

Same Syntax, Two Jobs

The three dots ... show up in a lot of modern JavaScript code, and they do two opposite things depending on where they appear. Once you see the pattern, every use of ... falls into one of two buckets:

  • Rest: ...name on the receiving side collects multiple values into one array or object.
  • Spread: ...value on the giving side expands an array or object into its individual pieces.

That's the whole mental model. The rest of this page is just examples of each, and the patterns you'll keep reaching for.

Rest Parameters: Collecting Arguments

A rest parameter in a function definition gathers any number of arguments into a real array:

index.js
Output
Click Run to see the output here.

nums is an ordinary array. You can .map it, .filter it, check its .length, pass it to another function — everything arrays do.

Rest parameters can mix with regular parameters, but the rest parameter has to come last:

index.js
Output
Click Run to see the output here.

label swallows the first argument; everything after it lands in items. Writing the rest parameter anywhere but last is a syntax error.

Rest vs. the Old arguments Object

Older JavaScript code uses a magic variable called arguments inside regular functions. It looks like an array but isn't one, which means array methods don't work on it directly. Rest parameters replace it cleanly:

index.js
Output
Click Run to see the output here.

Arrow functions don't even have an arguments object, so rest parameters are the only way to accept a variable number of arguments in them. Prefer ...args in any new code.

Spread in Function Calls

Spread does the reverse: it takes an array and unpacks it into individual arguments at the call site.

index.js
Output
Click Run to see the output here.

Math.max takes individual numbers, not an array. Before spread, you'd write Math.max.apply(null, nums). Now it's a ... and you're done.

Notice how the exact same ... is rest in the function definition and spread in the function call — the position tells you which one it is.

Spread in Array Literals

Spreading into an array literal copies or combines arrays:

index.js
Output
Click Run to see the output here.

[...a] gives you a fresh array with the same elements — useful when you want to sort or mutate without touching the original:

index.js
Output
Click Run to see the output here.

scores is untouched because .sort ran on the copy. Small habit, big payoff when you're writing code that shouldn't have surprising side effects.

Spread in Object Literals

Spread works on plain objects too, merging their properties into a new one:

index.js
Output
Click Run to see the output here.

Later keys win. updates.age overrides user.age, and city comes along for the ride. The order of the spreads determines the result — keep that in mind when you're stacking defaults and overrides:

index.js
Output
Click Run to see the output here.

Defaults first, user choices second. The user wins on fontSize, inherits theme.

The Shallow Copy Trap

Spread copies one level deep. Nested objects and arrays are still shared between the original and the copy:

index.js
Output
Click Run to see the output here.

Both arrays show the new tag because copy.tags and original.tags are the same array. Spread didn't clone the nested list — it just copied the reference.

For a true deep copy of plain data, reach for structuredClone:

index.js
Output
Click Run to see the output here.

Now the two arrays are independent. structuredClone is built into modern browsers and Node, handles nested structures, and is the right call whenever "shallow" won't cut it.

Rest in Destructuring

Rest works in destructuring too, where it collects the leftover elements or properties:

index.js
Output
Click Run to see the output here.

Pulling a few fields out and keeping the rest in a single object is a common pattern when forwarding props, stripping sensitive fields, or building patched versions of data:

index.js
Output
Click Run to see the output here.

password gets extracted (and ignored); safe holds everything else. No mutation, no manual copying.

A Quick Recap

  • ...name in a parameter list or destructuring pattern is rest: it collects.
  • ...value in a function call, array literal, or object literal is spread: it expands.
  • Spread copies are shallow. Nested structures stay shared. Use structuredClone for deep copies.
  • Rest parameters are real arrays — use them instead of arguments.
  • Later spreads override earlier ones in object literals, which is how you build defaults-plus-overrides.

Next: Closures

Functions in JavaScript don't just take inputs and return outputs — they also remember the scope they were defined in. That memory is called a closure, and it's the mechanism behind callbacks, factories, and most of the patterns you'll meet on the next page.

Frequently Asked Questions

What's the difference between rest and spread in JavaScript?

They use the same ... syntax but do opposite jobs. Rest collects multiple values into a single array — it shows up in function parameter lists and destructuring. Spread expands an iterable or object into its pieces — it shows up in function calls, array literals, and object literals. If ... is on the receiving side, it's rest; if it's on the giving side, it's spread.

How do rest parameters work in a function?

A rest parameter like function sum(...nums) collects every argument passed to the function into a real array named nums. It must be the last parameter in the list. Unlike the older arguments object, a rest parameter is a true array, so .map, .filter, and .reduce work directly on it.

Does the spread operator make a deep copy?

No. Spread copies one level only — a shallow copy. { ...user } gives you a new object with the same top-level keys, but nested objects and arrays inside are still shared references. For a deep copy, use structuredClone(value) or serialize through JSON for plain data.

Learn to code with Coddy

GET STARTED