JavaScript Rest & Spread (...) Explained with Examples

Rest and spread syntax use the same three-dot form in JavaScript, but they solve opposite problems. Rest collects values into a single array or object, while spread expands an array, object, or function arguments into individual items.

Quick answer: Use ... as rest when you want to gather values, and as spread when you want to unpack values. In functions, arrays, objects, and destructuring, the meaning depends on where the ... appears.

Difficulty: Beginner

You'll understand this better if you know: arrays, function parameters, objects, and basic destructuring in JavaScript.

Browser support: Widely available since Jul 2022 (and more below)

1. What Is JavaScript Rest & Spread (...)?

Rest and spread are two related uses of the same syntax token: the three-dot .... The meaning changes based on context.

  • rest collects multiple values into one array or object.
  • spread expands an array, object, or iterable into separate values.
  • Both are common in function arguments, array literals, object literals, and destructuring.
  • They help write shorter, clearer code without manually looping or copying values.

Because the same symbol does different jobs, beginners often confuse rest with spread. A good rule is: if the dots appear on the left side of an assignment pattern or parameter list, they usually collect values; if they appear inside an array, object, or function call, they usually expand values.

2. Why JavaScript Rest & Spread Matters

Rest and spread make JavaScript code easier to read and maintain. Instead of writing manual loops, slicing arrays, or building new objects step by step, you can express your intent directly.

They matter because they let you:

  • handle functions with flexible numbers of arguments,
  • copy or combine arrays and objects without mutating the original value,
  • pick out specific values while keeping the remaining ones together,
  • write cleaner code for destructuring data from APIs or application state.

They are especially useful in modern JavaScript codebases because they reduce boilerplate and make data transformation easier to follow.

3. Basic Syntax

Rest in function parameters

Use rest parameters when a function should accept any number of arguments. The rest parameter must be the last parameter in the list.

JavaScript
function sum(...numbers) {
  let total = 0;

  for (const number of numbers) {
    total += number;
  }

  return total;
}

Here, ...numbers collects all arguments into one array named numbers.

Spread in function calls

Use spread when you want to pass items from an array as separate arguments.

JavaScript
const values = [10, 20, 30];

Math.max(...values);

Here, ...values expands the array into separate arguments: Math.max(10, 20, 30).

Rest in destructuring

Use rest in destructuring to collect leftover values after matching the ones you want.

JavaScript
const [first, second, ...remaining] = ["a", "b", "c", "d"];

In this example, first and second get the first two values, and remaining gets the rest.

Spread in array and object literals

Use spread to create a new array or object that includes existing values.

JavaScript
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];

const user = { name: "Ava" };
const updatedUser = { ...user, role: "admin" };

This creates new values instead of changing the original array or object.

4. Step-by-Step Examples

Example 1: Sum any number of arguments

This function uses rest parameters so callers do not need to know how many numbers are expected.

JavaScript
function sum(...numbers) {
  return numbers.reduce((total, number) => total + number, 0);
}

sum(5, 10, 15);

The function receives three arguments, but rest puts them into one array so reduce can process them.

Example 2: Find the largest value in an array

Spread is useful when a function expects separate arguments, but your data is already in an array.

JavaScript
const scores = [72, 88, 91, 85];
const highest = Math.max(...scores);

Without spread, you would have to list each score manually. With spread, the array becomes individual arguments automatically.

Example 3: Copy and extend an array

Spread is a common way to make a new array from an existing one.

JavaScript
const baseTags = ["javascript", "functions"];
const allTags = [...baseTags, "syntax", "rest"];

The new array contains all original items plus two more. The original array stays unchanged.

Example 4: Pick values with object rest

Object rest is useful when you want one or two properties and want the rest grouped together.

JavaScript
const profile = {
  id: 42,
  name: "Mina",
  role: "editor",
  active: true
};

const { id, ...details } = profile;

After destructuring, id contains one value, and details contains the remaining properties.

5. Practical Use Cases

  • Forwarding arguments from one function to another without writing a custom loop.
  • Creating immutable updates to arrays and objects in application state.
  • Combining default data with overrides, such as configuration objects.
  • Writing utility functions that accept a variable number of inputs.
  • Removing selected properties while keeping the rest for logging or API calls.

These patterns are common in everyday JavaScript code, especially when working with lists, configuration, and data shaping.

6. Common Mistakes

Mistake 1: Using rest anywhere in a parameter list

Rest parameters must come last. If you place another parameter after them, JavaScript cannot know where the collected arguments should stop.

Problem: This function signature is invalid because the rest parameter is not the final parameter.

JavaScript
function joinNames(...names, separator) {
  return names.join(separator);
}

Fix: Put required parameters first, then the rest parameter at the end.

JavaScript
function joinNames(separator, ...names) {
  return names.join(separator);
}

The corrected version works because JavaScript can read the fixed parameter first and then collect the remaining arguments.

Mistake 2: Thinking spread mutates the original array or object

Spread creates a new array or object. It does not modify the original value, so changing the copy does not update the source.

Problem: Developers sometimes expect the original data to change when they edit the copied value.

JavaScript
const original = [1, 2];
const copy = [...original];

copy.push(3);

Fix: If you want a new value, use spread and then work with the new array or object explicitly.

JavaScript
const original = [1, 2];
const updated = [...original, 3];

The corrected version is predictable because it clearly creates a separate value instead of changing the original.

Mistake 3: Spreading a value that is not iterable

Array spread requires an iterable, such as an array, string, set, or map. If you try to spread a plain object into an array, JavaScript throws a runtime error such as TypeError: object is not iterable or is not iterable.

Problem: Plain objects cannot be expanded inside an array literal because they do not implement the iterable protocol.

JavaScript
const user = { name: "Kai", age: 29 };
const items = [...user];

Fix: Spread arrays into arrays, and spread objects into objects.

JavaScript
const user = { name: "Kai", age: 29 };
const copy = { ...user };

The corrected version works because object spread copies properties into another object instead of trying to build an array.

7. Best Practices

Prefer rest for flexible function APIs

When a function accepts an unknown number of values, rest parameters make the API simpler and easier to call.

JavaScript
function average(...numbers) {
  if (numbers.length === 0) {
    return 0;
  }

  const total = numbers.reduce((sum, number) => sum + number, 0);
  return total / numbers.length;
}

This keeps the function easy to extend without changing every caller.

Use spread to create new data instead of mutating old data

Spread is a clean way to build updated arrays and objects while preserving the original value.

JavaScript
const settings = { theme: "light", language: "en" };
const nextSettings = { ...settings, theme: "dark" };

This pattern is especially useful when you want predictable state updates.

Be careful with shallow copies

Spread copies only the top level. Nested arrays and objects are still shared references unless you copy them separately.

JavaScript
const original = {
  name: "Rin",
  profile: { city: "Tokyo" }
};

const copy = { ...original };
copy.profile.city = "Osaka";

Because profile is still shared, this change affects both objects. If you need deep cloning, spread alone is not enough.

8. Limitations and Edge Cases

  • Object spread is a shallow copy, so nested objects and arrays are still shared.
  • Rest parameters only work in function parameter lists and destructuring patterns, not in ordinary expressions.
  • Array spread requires an iterable value; plain objects cannot be spread into arrays.
  • Object spread copies enumerable own properties, so it does not copy the prototype chain or non-enumerable properties.
  • Spread does not preserve special object behavior such as class instances, methods on prototypes, or property descriptors.
  • Rest parameters always produce a real array, even if the caller passed an array-like object.

Note: If you need to copy a class instance, preserve methods, or duplicate nested data deeply, you need a different approach than spread.

9. Practical Mini Project

Let’s build a small utility for merging default settings with user overrides and printing a summary. This shows rest and spread working together in a realistic way.

JavaScript
function createReport(...tags) {
  const defaults = {
    title: "Weekly Summary",
    author: "System",
    published: false
  };

  const report = {
    ...defaults,
    tags
  };

  return report;
}

const result = createReport("javascript", "functions", "spread");

console.log(result);
Output✓ Tested · Node 24
{ title: "Weekly Summary", author: "System", published: false, tags: [ "javascript", "functions", "spread" ] }

This example uses rest to collect all tag arguments into one array and spread to build a new report object from defaults. The output is a plain object with a tags array and the default properties already filled in.

10. Key Points

  • Rest collects values; spread expands values.
  • Use rest in function parameters and destructuring.
  • Use spread in function calls, arrays, and objects.
  • Spread creates a shallow copy, not a deep clone.
  • Rest parameters must be last in a parameter list.
  • Array spread needs an iterable value.

11. Practice Exercise

  • Write a function named buildPlaylist that accepts any number of song titles.
  • Use rest parameters to collect the titles into one array.
  • Return a new object with a songs property and a count property.
  • Expected output: an object like { songs: ["Intro", "Verse", "Chorus"], count: 3 }.

Hint: Use ...songs in the function parameters, then spread or direct assignment when building the return object.

Show solution
JavaScript
function buildPlaylist(...songs) {
  return {
    songs,
    count: songs.length
  };
}

const playlist = buildPlaylist("Intro", "Verse", "Chorus");

console.log(playlist);
Output✓ Tested · Node 24
{ songs: [ "Intro", "Verse", "Chorus" ], count: 3 }

Browser Support

FeatureChromeEdgeFirefoxSafariSafari iOS
Spread syntax
Widely available since Jul 2022
60+79+55+11.1+11.3+
Destructuring
Widely available since Jul 2022
60+79+55+11.1+11.3+

Minimum versions with full support. Data from web-features 3.43.0 (the data behind MDN's Baseline), updated at every site build.

12. Final Summary

JavaScript rest and spread syntax share the same three-dot notation, but their jobs are different. Rest gathers values into an array or object, while spread expands values so they can be used individually. Once you recognize the context, the syntax becomes easy to read and use.

In practice, rest is ideal for flexible function parameters and destructuring leftover values, while spread is ideal for copying, combining, and passing data. Just remember that spread is shallow, rest must appear in the right place, and array spread only works with iterables.

If you want to keep learning, next explore destructuring in more depth and compare shallow copies with deep copies so you can use spread confidently in real projects.