Destructuring, Spread & Rest
Destructuring unpacks values from arrays and objects into separate variables in one step. Spread syntax (...) does the opposite, expanding an array or object into individual pieces. Together they make code that copies, merges and extracts data far shorter and clearer.
Array destructuring
const rgb = [214, 51, 108]; const [red, green, blue] = rgb; console.log(red, green, blue); const [first, , third] = ["a", "b", "c"]; console.log(first, third); const [x = 0, y = 0] = [5]; console.log(x, y);
214 51 108 a c 5 0
Variables are matched by position. Skip positions with an empty slot, and provide defaults with = for missing values.
Swapping variables
let a = 1; let b = 2; [a, b] = [b, a]; console.log(a, b);
2 1
Object destructuring
const user = { name: "Ana", age: 30, email: "ana@example.com" }; const { name, age } = user; console.log(name, age); const { email: contact, role = "member" } = user; console.log(contact, role);
Ana 30 ana@example.com member
Variables are matched by property name, so order doesn't matter. email: contact reads the email property into a variable named contact; role = "member" provides a default when the property is missing.
Nested destructuring
const order = { id: 7, customer: { name: "Kai", address: { city: "Oslo" } }, items: ["tea", "cake"], }; const { customer: { name, address: { city } }, items: [firstItem], } = order; console.log(name, city, firstItem);
Kai Oslo tea
Deep patterns are powerful but can get hard to read — two levels is usually the practical limit.
Destructuring in parameters
This is where destructuring is used most — pulling exactly the fields a function needs:
function describe({ name, price, currency = "USD" }) { return `${name}: ${price} ${currency}`; } const entries = Object.entries({ apples: 3, pears: 5 }); for (const [fruit, count] of entries) { console.log(fruit, count); } console.log(describe({ name: "Lamp", price: 30 }));
apples 3 pears 5 Lamp: 30 USD
Spread with arrays
const weekdays = ["Mon", "Tue", "Wed"]; const weekend = ["Sat", "Sun"]; const week = [...weekdays, "Thu", "Fri", ...weekend]; console.log(week.join(" ")); const copy = [...weekdays]; copy.push("extra"); console.log(weekdays.length, copy.length); console.log(Math.max(...[4, 9, 2])); console.log([..."hi!"]);
Mon Tue Wed Thu Fri Sat Sun 3 4 9 [ 'h', 'i', '!' ]
Spread with objects
const defaults = { theme: "light", fontSize: 14, autosave: true }; const userPrefs = { theme: "dark" }; const settings = { ...defaults, ...userPrefs }; console.log(settings); const updated = { ...settings, fontSize: 16 }; console.log(updated.fontSize, settings.fontSize);
{ theme: 'dark', fontSize: 14, autosave: true }
16 14Later properties win, so spreading defaults first and overrides second is the standard way to merge settings. Creating an updated copy instead of changing the original is essential in frameworks like React.
Rest in destructuring
In a destructuring pattern, ... collects "everything else":
const [winner, ...others] = ["Mia", "Leo", "Ava", "Sam"]; console.log(winner, others); const { password, ...safeUser } = { id: 1, name: "Ana", password: "secret" }; console.log(safeUser);
Mia [ 'Leo', 'Ava', 'Sam' ]
{ id: 1, name: 'Ana' }The second example is a neat way to remove a property without changing the original object.
Shallow copies
Spread only copies one level deep. Nested objects are still shared:
const original = { name: "Ana", tags: ["admin"] }; const shallow = { ...original }; shallow.tags.push("editor"); console.log(original.tags); const deep = structuredClone(original); deep.tags.push("viewer"); console.log(original.tags, deep.tags);
[ 'admin', 'editor' ] [ 'admin', 'editor' ] [ 'admin', 'editor', 'viewer' ]
structuredClone makes a full deep copy of plain data (objects, arrays, dates, maps and more — though not functions or class instances' methods).