Destructuring, Spread & Rest
Intermediate · 18 min read · ▶ live playground · ✦ checkpoint
Once your data has shape, repeating player.name, player.score, and player.rank everywhere starts to feel noisy. Destructuring lets you pull useful pieces out of objects and arrays in one move, while spread and rest let you copy, merge, and collect data without writing every property by hand.
Destructure objects by property name
Destructuring puts a pattern on the left side of =. For objects, the pattern names the properties you want.
const player = {
name: "Mina",
score: 18,
rank: "gold",
};
const { score, name } = player;
console.log(name);
console.log(score);
console.log(player.rank);→ Mina, 18, then gold.
Object destructuring is not position-based. The pattern says "find the score property" and "find the name property", even though score appears after name in the object. It also does not remove anything from the object. player.rank is still there because destructuring reads properties; it does not delete them.
Think of destructuring as opening the labeled card from 7.1 and placing a few labels on your desk as local names. You still have the original card.
Defaults and renaming
Object destructuring can do two common jobs while it reads: supply a default and choose a different local name.
const player = {
name: "Mina",
score: 18,
};
const {
name: playerName,
score: points,
rank = "rookie",
} = player;
console.log(playerName);
console.log(points);
console.log(rank);→ Mina, 18, rookie.
Read name: playerName as "read the name property, create the local name playerName." This is renaming, and it is useful when the property name is too vague for the place you are using it.
Read rank = "rookie" as "if rank is missing or undefined, use "rookie"." Destructuring defaults do not run for ordinary falsy values like 0, false, or ""; those are real values and are kept.
Array destructuring is positional
Array items are usually read by position, not by semantic property names. Array destructuring uses positions.
const scores = [21, 17];
const names = ["Mina", "Rae"];
const [topScore, secondScore, thirdScore = 0] = scores;
const [firstName, , thirdName = "Noor"] = names;
console.log(topScore);
console.log(secondScore);
console.log(thirdScore);
console.log(firstName);
console.log(thirdName);→ 21, 17, 0, Mina, then Noor.
The first name on the left gets index 0, the second gets index 1, and so on. The empty comma in [firstName, , thirdName] skips index 1. thirdName receives its default because index 2 is missing.
Use array destructuring when the positions mean something obvious: first and second score, row and column, start and end. If the meaning is not obvious, an object with named properties is kinder to readers.
Try it — unpack the shape
Run this, then change savedTheme to "highContrast" and remove rank from player. At the › prompt, inspect player, settings, and otherScores.
Notice that the same data can be read in different styles: object destructuring follows labels, array destructuring follows positions, and rest gathers whatever positions are left.
Spread clones and merges
The ... token means spread when it appears inside a new array or object. Spread expands the values from an existing array or object into the new one.
const defaultSettings = {
theme: "light",
pageSize: 20,
};
const savedSettings = {
pageSize: 50,
};
const settings = {
...defaultSettings,
...savedSettings,
theme: "dark",
};
const names = ["Mina", "Rae"];
const roster = ["Kai", ...names, "Noor"];
console.log(defaultSettings.pageSize);
console.log(settings.pageSize);
console.log(settings.theme);
console.log(roster[0]);
console.log(roster[2]);
console.log(roster[3]);→ 20, 50, dark, then Kai, Rae, Noor.
For objects, later properties win. savedSettings.pageSize overwrites defaultSettings.pageSize, and the final theme: "dark" overwrites the earlier theme. This pattern is everywhere in real JavaScript: start with defaults, spread in saved or user-chosen values, then set the final overrides explicitly.
For arrays, spread inserts the existing elements into the new array. roster is a new array that starts with "Kai", then includes the names, then ends with "Noor".
Spread copies one level
Spread is excellent for top-level copies, but it is not a deep copy. If a property holds another object or array, the spread copy still points at that nested value.
const original = {
name: "Mina",
stats: {
score: 18,
},
};
const copy = {
...original,
};
copy.name = "Rae";
copy.stats.score = 99;
console.log(original.name);
console.log(copy.name);
console.log(original.stats.score);
console.log(copy.stats.score);→ Mina, Rae, then 99, 99.
This is not a reason to avoid spread. It is a reason to know what shape you are copying. For flat objects, spread is often exactly what you want. For nested data, be deliberate about which nested pieces should also become new.
Rest collects everything else
The same ... token means rest when it appears in a destructuring pattern. Spread pours values out; rest gathers leftovers in.
const player = {
name: "Mina",
score: 18,
rank: "gold",
city: "Pune",
};
const scores = [21, 17, 9];
const { name, ...details } = player;
const [topScore, ...otherScores] = scores;
console.log(name);
console.log(details.score);
console.log(details.rank);
console.log(details.name);
console.log(topScore);
console.log(otherScores[0]);
console.log(otherScores.length);→ Mina, 18, gold, undefined, then 21, 17, 2.
details gets every property except name, so details.name is undefined. otherScores gets every array element after the first one. Rest must come last because "everything else" only makes sense after you have named the pieces you want to pull out.
Checkpoint
Answer all three to mark this lesson complete
Destructuring, spread, and rest are small syntax tools with a big payoff: less repeated property access and clearer data reshaping. Next, 7.3 adds behavior to objects with methods, then gives you the first careful model of this.