Learn the JavaScript spread operator (...) and rest parameters with runnable code. Merge objects, clone arrays, collect function arguments, and more.
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.
[...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.
fn(...args) expands an array into individual arguments, replacing the old fn.apply(null, args). Math.max(...numbers) is the canonical example.
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.
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.
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.
// 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));
Open this example in the TryJS playground to edit and run the code instantly in your browser — no signup needed.
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.
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.
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 })].
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.