JavaScript60 min total · 16 parts
JavaScript Array and Object Methods Cheat Sheet
Part 8 of 16 · ~2 min
Spread and Rest
Spread (...) unpacks an array's elements — or, written on an object instead, its own enumerable fields — right at the spot where you wrote the three dots. That's what makes it the go-to way to copy or merge something without laying a finger on the original.
const shortlist = [...candidates, { id: "c6", name: "New Applicant", role: "backend", score: 70, status: "active" }];
// candidates itself has 5 entries still; shortlist has 6
const updatedSam = { ...candidates[3], status: "hired" };
// a new object — candidates[3].status is still "active", updatedSam.status is "hired"
That second example is the pattern worth internalizing: to change one field on a candidate without mutating the shared record, spread the old object and override just the field that changed.
Inside a function's parameter list, though, those same three dots mean something else entirely — rest, which collects whatever arguments are left over into a genuine array:
function averageOf(...ratings) { // rest — every argument collected into one array
return ratings.reduce((sum, r) => sum + r, 0) / ratings.length;
}
averageOf(8, 7, 9); // 8 — three interviewers' ratings for one category, averaged
function describeCandidate(name, ...scores) { // rest can follow named parameters too
console.log(name, scores); // "Priya Shah", [82, 90, 75]
}
describeCandidate("Priya Shah", 82, 90, 75);
There's a real limit to what spread duplicates, though — it only goes one level deep. Anything nested inside — an array sitting inside an object, say — comes along as a shared reference rather than a fresh copy. Object.assign() has the identical blind spot:
const original = candidates[0]; // Priya, with a `tags` array nested inside
const copy = { ...original };
copy.tags.push("kubernetes");
console.log(original.tags); // ["node", "postgres", "kubernetes"] — the array was never actually copied
structuredClone(obj) works differently — a global function, available in modern runtimes, that walks the entire structure and duplicates it at every level, Maps, Sets, and Dates included, so nothing nested is left pointing back at the source object. It's what most people reach for now instead of the older JSON.parse(JSON.stringify(obj)) workaround, which has quieter failure modes of its own: it throws functions away entirely, throws undefined away entirely, and forces anything else non-standard through whatever JSON happens to allow. A candidate's appliedOn field, if it started life as a real Date object, comes out of that particular round trip as a plain string instead — and nothing about the call warns you it happened.