Spread & Rest Operators

Three little dots — ... — do two opposite jobs depending on where you write them. As spread they pour a collection out into its pieces; as rest they scoop loose pieces back into one collection.

Learn Spread & Rest Operators in our free JavaScript course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a quick…

Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

They power immutable updates in React/Redux, neat array merges, and flexible function signatures. Master both halves of the ... and your code gets noticeably cleaner.

📚 Prerequisites: Finish Destructuring first — rest in destructuring builds directly on it. Comfort with arrays, objects, and functions is assumed.

💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:

🎒 Real-World Analogy: Think of a backpack full of items :

Put ...arr inside a new array literal and its elements are dropped in place. This gives you a quick copy (a new array, not a reference) and an easy way to merge — no concat needed. This pattern is the backbone of immutable state updates.

The same trick works for objects. Spread an object into a new {' '} to clone it, then add or replace keys. Because later keys win, this is the standard way to apply overrides on top of defaults — and to update one field without mutating the original.

When a function wants separate arguments but your values live in an array, spread bridges the gap. This is the modern, readable replacement for the old fn.apply(null, arr) trick you may have seen.

In a function's parameter list, ...args gathers every remaining argument into a real array. Unlike the old arguments object, you can use map / filter / reduce on it directly. The rest parameter must be last.

Rest also works on the left side, inside a destructuring pattern. Pull off the first item (or a couple of named keys) and gather everything else into a new array or object — perfect for "take the head, keep the tail" or "remove one field" operations.

Spread only copies the top level . Nested objects and arrays are still shared by reference, so mutating them in the "copy" silently changes the original. For a fully independent copy of nested data, reach for structuredClone() .

Write a rest parameter that collects all numbers, then return how many there are.

These lines are scrambled. Reorder them so it logs the merged, overridden object.

Why: both source objects must exist before you spread them, and overrides comes last so its role wins.

Predict the output before revealing the answer.

{' '} — the last spread wins, so the second a overwrites the first.

[ 2, 3 ] — a takes the first item; rest gathers everything else into an array.

2 — rest collects both arguments into the array n , whose length is 2.

Up next: map, filter & reduce — transform whole arrays without a single loop. 🔁

Practice quiz

Where does the ... act as SPREAD rather than rest?

  • In a function's parameter list
  • On the left of = in a destructuring pattern
  • Inside an array/object literal or function call
  • It is always rest

Answer: Inside an array/object literal or function call. On the right side (inside literals or calls) the dots spread a collection out into pieces.

What does { ...{ a: 1 }, ...{ a: 2 } } evaluate to?

  • { a: 2 }
  • { a: 1 }
  • { a: 1, a: 2 }
  • { a: 3 }

Answer: { a: 2 }. When keys collide in a merge, the last spread wins, so a becomes 2.

Is a spread copy deep or shallow?

  • Deep — fully independent
  • It depends on the array length
  • It throws for nested data
  • Shallow — nested objects are still shared by reference

Answer: Shallow — nested objects are still shared by reference. Spread copies only the top level; nested objects/arrays remain shared, so use structuredClone for a deep copy.

What does Math.max(...[88, 95, 100, 64]) return?

  • 88
  • 100
  • 95
  • 64

Answer: 100. Spread turns the array into separate arguments, so Math.max receives 88, 95, 100, 64 and returns 100.

What does [..."hello"] produce?

Strings are iterable, so spreading yields an array of individual characters.

Given const [head, ...tail] = [10, 20, 30, 40], what is tail?

  • 10

head takes the first element; rest gathers the remaining elements into a new array.

Why must a rest parameter come last? function f(...nums, last) is...

  • Valid
  • A SyntaxError
  • Slower
  • Equivalent to (last, ...nums)

Answer: A SyntaxError. A rest parameter must be the final parameter; otherwise it is a SyntaxError.

What advantage do rest parameters have over the legacy arguments object?

  • They are array-like only
  • They work only in arrow functions
  • They are slower but clearer
  • They give you a real array with map/filter/reduce

Answer: They give you a real array with map/filter/reduce. Rest parameters produce a real array, so array methods work directly; arguments is only array-like.

Given const account = { id: 1, password: "x", name: "Ivy" } and const { password, ...safe } = account, what is safe?

  • { password: "x" }
  • { id: 1, name: "Ivy" }
  • { id: 1, password: "x", name: "Ivy" }
  • undefined

Answer: { id: 1, name: "Ivy" }. Pulling off password and gathering the rest removes that key, leaving { id: 1, name: 'Ivy' }.

Which produces the correct override of defaults with theme: "dark"?

  • { theme: "dark", ...defaults }
  • { ...defaults, ..."dark" }
  • { ...defaults, theme: "dark" }
  • { defaults, theme: "dark" }

Answer: { ...defaults, theme: "dark" }. Spread defaults first, then your override last so its key wins.