Spread Operator

Three dots (...) that expand iterables into individual elements.

Array Spread

Expand an array into individual elements.

// Spread "unpacks" an array:
const nums = [1, 2, 3];
console.log(...nums); // 1 2 3 (separate arguments)

// Insert into another array:
const more = [0, ...nums, 4, 5];
// [0, 1, 2, 3, 4, 5]

// Pass array as function arguments:
function add(a, b, c) { return a + b + c; }
add(...nums); // 6  (same as add(1, 2, 3))

// Math.max with arrays:
const scores = [85, 92, 78, 95, 88];
Math.max(...scores); // 95
Math.min(...scores); // 78

// Convert iterable to array:
const chars = [..."hello"]; // ["h", "e", "l", "l", "o"]
const unique = [...new Set([1, 2, 2, 3])]; // [1, 2, 3]

Object Spread

Copy and extend objects immutably.

// Spread object properties into a new object:
const defaults = { theme: "light", lang: "en", debug: false };
const userPrefs = { theme: "dark", lang: "ja" };

const config = { ...defaults, ...userPrefs };
// { theme: "dark", lang: "ja", debug: false }
// Later spreads overwrite earlier ones!

// Add/override properties:
const user = { name: "Alice", age: 25 };
const updated = { ...user, age: 26, email: "a@b.com" };
// { name: "Alice", age: 26, email: "a@b.com" }

// Remove a property (with destructuring):
const { age, ...withoutAge } = user;
// withoutAge = { name: "Alice" }

// Conditional properties:
const post = {
  title: "Hello",
  ...( isPublished && { publishedAt: new Date() }),
  ...( tags.length && { tags }),
};

Copying

Spread creates shallow copies — understand the limits.

// Shallow copy of arrays:
const original = [1, 2, 3];
const copy = [...original];

copy.push(4);
console.log(original); // [1, 2, 3] (unchanged)
console.log(copy);     // [1, 2, 3, 4]

// Shallow copy of objects:
const obj = { a: 1, b: 2 };
const clone = { ...obj };

clone.c = 3;
console.log(obj);   // { a: 1, b: 2 } (unchanged)
console.log(clone); // { a: 1, b: 2, c: 3 }

Spread creates a new array/object — modifying the copy doesn't affect the original.

1 / 2

Merging

Combine arrays and objects together.

// Merge arrays:
const front = ["React", "Vue"];
const back = ["Node", "Django"];
const fullStack = [...front, ...back];
// ["React", "Vue", "Node", "Django"]

// Merge + deduplicate:
const all = [...new Set([...front, ...back, ...front])];

// Merge objects (last wins):
const base = { size: "md", color: "blue", variant: "solid" };
const override = { color: "red", size: "lg" };
const merged = { ...base, ...override };
// { size: "lg", color: "red", variant: "solid" }

// Order matters!
const a = { x: 1, y: 2 };
const b = { y: 3, z: 4 };
{ ...a, ...b } // { x: 1, y: 3, z: 4 } — b's y wins
{ ...b, ...a } // { x: 1, y: 2, z: 4 } — a's y wins

Practical Patterns

Real-world uses of spread.

// 1. Immutable state updates (React):
const [todos, setTodos] = useState([]);
// Add:
setTodos([...todos, newTodo]);
// Remove:
setTodos(todos.filter(t => t.id !== id));
// Update one:
setTodos(todos.map(t => t.id === id ? { ...t, done: true } : t));

// 2. Function composition:
function withDefaults(options) {
  return { method: "GET", headers: {}, ...options };
}
withDefaults({ url: "/api" }); // { method: "GET", headers: {}, url: "/api" }

// 3. Array manipulation without mutation:
const arr = [1, 2, 3, 4, 5];
// Prepend:  [0, ...arr]
// Append:   [...arr, 6]
// Insert:   [...arr.slice(0, 2), 99, ...arr.slice(2)]
// Remove:   [...arr.slice(0, 1), ...arr.slice(2)]

// 4. Convert NodeList to Array:
const divs = [...document.querySelectorAll("div")];
divs.map(d => d.textContent); // now array methods work

FAQ

Common questions about the spread operator.