tryjs.app

JavaScript Spread & Rest Operator — Examples and Differences

Learn the JavaScript spread operator (...) and rest parameters with runnable code. Merge objects, clone arrays, collect function arguments, and more.

Spread & Rest

Spread operator and rest parameters

javascriptJS Fundamentals
// Merge objects — later keys win
const defaults = { theme: "dark", lang: "en", fontSize: 14 };
const prefs = { theme: "light", fontSize: 16 };
const config = { ...defaults, ...prefs };
console.log(config);

// Clone + extend arrays (shallow)
const base = [1, 2, 3];
const extended = [...base, 4, 5, ...base];
console.log(extended);

// Spread in function call
const nums = [5, 2, 8, 1, 9];
console.log("Max:", Math.max(...nums));

// Rest parameters
function sum(first, ...others) {
  return others.reduce((acc, n) => acc + n, first);
}
console.log(sum(1, 2, 3, 4, 5));

Overview

The three-dot syntax (...) does two different jobs depending on where it appears. As the spread operator, it expands an iterable (array, string, set) or an object's own enumerable properties into another array or object literal. As rest parameters, it collects the remaining function arguments into an array. Same tokens, opposite directions: spread unpacks, rest packs.

How It Works

Spread in array and object literals

[...arr] creates a shallow copy of an array. { ...obj } creates a shallow copy of an object's own enumerable properties. Later entries override earlier ones, which is why defaults-then-overrides patterns work.

Spread in function calls

fn(...args) expands an array into individual arguments, replacing the old fn.apply(null, args). Math.max(...numbers) is the canonical example.

Rest parameters

function f(first, ...rest) collects all arguments after first into an array named rest. Unlike the old arguments object, rest is a real array and only captures what comes after named parameters.

Shallow, not deep

Spread copies one level deep. Nested objects and arrays are still shared between the original and the copy. For a true deep clone use structuredClone() or a library.

Common Mistakes

  • Thinking spread does a deep clone — it doesn't. Nested objects remain shared.
  • Using spread on non-iterable values in array context (e.g. [...null] throws).
  • Forgetting that the order of spreads in an object literal matters — { ...a, ...b } lets b override a.
  • Mixing up spread (in literals and calls) with rest (in function parameters) — same symbol, opposite direction.

When to Use It

Use spread to clone or merge arrays and objects without mutation, to pass an array as separate arguments, and to build immutable updates (Redux-style). Use rest to write variadic functions that take any number of arguments.

Frequently Asked Questions

What is the difference between spread and rest in JavaScript?

They use the same ... syntax but do opposite things. Spread expands an iterable into individual elements ([...arr]). Rest collects remaining elements into an array (function f(...args)). The distinction is where they appear — a literal/call site vs a parameter list.

Does spread do a deep copy?

No. Spread is always shallow: top-level elements are copied, but nested objects and arrays are shared references. For a deep clone use structuredClone(obj) (built-in) or a library like lodash's cloneDeep.

Can I spread an object into an array?

No. Object spread only works inside object literals, and array spread requires an iterable. [...{ a: 1 }] throws because a plain object is not iterable. Convert first: [...Object.entries({ a: 1 })].

How does spread merge objects with conflicting keys?

Later sources win. In { ...defaults, ...overrides } any key present in overrides replaces the one from defaults. This makes spread perfect for the 'defaults + user prefs' pattern.