Spread and Rest Syntax

Course: JavaScript Intermediate

Lesson 8: Spread and Rest Syntax

Level

Intermediate

Estimated Reading Time

10–15 minutes

Goal

By the end of this lesson, the learner will be able to:

  • Use the spread operator ... to expand arrays and objects
  • Use rest parameters ...args to collect multiple function arguments
  • Distinguish between copying by value and copying by reference when spreading

Frontend Development Context

Spread syntax is one of the most frequently used features in modern JavaScript and React. When you update state in React, you spread the existing state into a new object and override only the changed property — this is how you avoid mutating state directly. When you merge two arrays or combine configuration objects, spread does it in a single line.

Rest parameters are the other side of the same coin. They let functions accept any number of arguments without knowing in advance how many there will be. This pattern appears in logging utilities, validation helpers, and any function that needs to be flexible about its inputs.

Explanation

The spread operator ... expands an iterable (array, string, or other iterable) or an object into individual elements. In an array context, [...arr1, ...arr2] creates a new array containing all elements from both. In an object context, { ...obj1, ...obj2 } creates a new object with all properties from both, with later properties overriding earlier ones if names conflict.

Spread creates a shallow copy. For arrays and objects with only primitive values, this effectively creates an independent copy. For arrays or objects containing nested objects or arrays, the nested values are still shared references — modifying them in the copy also modifies the original.

Rest parameters use the same ... syntax but in the opposite direction: instead of expanding a collection into individual values, rest collects individual values into an array. In a function signature, function logAll(...messages) means any number of arguments are collected into the messages array. The rest parameter must be the last parameter in the function signature.

Spread and rest are syntactically identical (...) but serve opposite purposes. Context determines which one applies: spread expands, rest collects.

You can also use spread to pass array elements as individual arguments to a function: Math.max(...numbers) rather than Math.max(numbers[0], numbers[1], ...).

Code Example

This example shows spread on arrays, spread on objects, rest parameters, and passing an array as function arguments with spread.

// Spread to combine arrays
const basics = ["variables", "functions", "loops"];
const advanced = ["closures", "prototypes"];
const allTopics = [...basics, "scope", ...advanced];
console.log(allTopics);
// ["variables", "functions", "loops", "scope", "closures", "prototypes"]

// Spread to copy and update an object
const defaultSettings = { theme: "light", fontSize: 14, language: "en" };
const userSettings = { ...defaultSettings, theme: "dark", fontSize: 16 };
console.log(userSettings);
// { theme: "dark", fontSize: 16, language: "en" }

// Rest parameters — collect any number of arguments into an array
function logMessages(prefix, ...messages) {
  messages.forEach(msg => console.log(`[${prefix}] ${msg}`));
}
logMessages("INFO", "App started", "User loaded", "Data ready");
// [INFO] App started
// [INFO] User loaded
// [INFO] Data ready

// Spread to pass array as individual arguments
const scores = [88, 92, 76, 100, 55];
console.log(Math.max(...scores)); // 100

Code Explanation

[...basics, "scope", ...advanced] creates a new array by expanding basics, inserting the string "scope", then expanding advanced. The result is a single flat array. Neither basics nor advanced is modified.

{ ...defaultSettings, theme: "dark", fontSize: 16 } starts with all properties from defaultSettings, then overrides theme and fontSize with new values. language is carried over unchanged. Properties declared later in the spread override earlier ones — this is the standard pattern for updating objects without mutation.

function logMessages(prefix, ...messages) shows rest parameters. prefix is a normal named parameter that receives the first argument. ...messages collects everything after the first argument into an array. Inside the function, messages is a standard array you can iterate over.

Math.max(...scores) shows spread in a function call context. Math.max expects individual number arguments, not an array. Spreading the array expands it into the argument list, equivalent to writing Math.max(88, 92, 76, 100, 55).

Pattern Highlights

Positive Pattern: Use object spread to update objects without mutation: const updated = { ...original, changedKey: newValue }. This is the standard immutable update pattern used in React state management.

⚠️ Neutral Note: Spread creates a shallow copy. If your object has nested arrays or objects as values, those nested structures are still shared between the original and the copy.

Negative Pattern: Do not use spread inside a tight loop to clone large objects repeatedly. Each spread creates a new object — in performance-sensitive code, this can cause unnecessary memory allocation.

Common Mistakes

Mistake 1: Expecting spread to deep-clone nested objects

Assuming spread fully isolates the copy from the original.

const original = { name: "Sam", scores: [10, 20, 30] };
const copy = { ...original };
copy.scores.push(40);
console.log(original.scores); // [10, 20, 30, 40] — original was mutated!

scores is an array (a reference type). Both original.scores and copy.scores point to the same array. Use structured clone or manually spread nested structures to avoid this.

Mistake 2: Putting the rest parameter in the wrong position

Placing ...rest before other named parameters.

function example(...values, last) { // SyntaxError
  console.log(last);
}

Rest parameters must be last in the parameter list. JavaScript does not know where to stop collecting values if rest is not at the end.

Mistake 3: Using spread to merge arrays expecting deduplication

Spreading two arrays and expecting duplicates to be removed.

const a = [1, 2, 3];
const b = [2, 3, 4];
const merged = [...a, ...b];
console.log(merged); // [1, 2, 3, 2, 3, 4] — duplicates remain

Spread simply concatenates — it does not deduplicate. If you need unique values, use new Set([...a, ...b]) and spread the result back into an array.

Quick Recap

  • Spread (...) expands an array or object into individual values — use it to combine arrays, clone objects, or pass arrays as function arguments
  • Object spread copies all properties and later properties override earlier ones with the same name
  • Rest parameters (...args) collect all remaining function arguments into an array — they must be the last parameter
  • Spread creates a shallow copy: nested objects and arrays are still references, not independent copies

Ready to test your understanding? Take the quiz to reinforce what you learned.

© 2026 Ant Skillsv.26.07.07-23:01
Ant Skills - Spread and Rest Syntax