Destructuring pulls values out of arrays and objects into variables. Spread does the opposite, expanding an array or object into a new one. Rest collects "everything else" into one variable. All three use short syntax you will see in almost every modern codebase, so it pays to read them fluently.
Object destructuring
Instead of reading properties one at a time:
const course = { title: 'JavaScript Complete Course', level: 'Beginner', lessons: 54 };
// The long way:
// const title = course.title;
// const level = course.level;
you can unpack them in one statement. The variable names match the property names:
const { title, level } = course;
console.log(title); // → JavaScript Complete Course
console.log(level); // → Beginner
Properties you do not mention are ignored. A property that does not exist gives undefined.
Renaming and defaults
Use a colon to store a property under a different name, and = to give a default for when the property is undefined:
const { title: courseTitle, updated = 'unknown' } = course;
console.log(courseTitle); // → JavaScript Complete Course
console.log(updated); // → unknown
Read title: courseTitle as "take title and put it in courseTitle". The default only applies to undefined, not to null, 0 or an empty string.
Nested objects
Destructuring patterns can mirror nested data:
const user = {
name: 'Amira',
settings: { theme: 'dark', fontSize: 18 },
};
const { name, settings: { theme } } = user;
console.log(name, theme); // → Amira dark
Here settings is a path, not a variable. Only name and theme are created. If user.settings were missing, this would throw a TypeError, so add a default when the nested object is optional: settings: { theme } = {}.
Array destructuring
Arrays destructure by position rather than by name:
const scores = [92, 78, 85];
const [first, second] = scores;
console.log(first, second); // → 92 78
Skip positions with an empty slot, and swap two variables without a temporary one:
const [, , third] = scores;
console.log(third); // → 85
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // → 2 1
Array destructuring works with anything iterable, so you will also see it with Object.entries (next lesson) and with functions that return two values:
function minMax(numbers) {
return [Math.min(...numbers), Math.max(...numbers)];
}
const [low, high] = minMax(scores);
console.log(low, high); // → 78 92
Destructuring parameters
This is where destructuring earns its keep. A function that takes an options object can unpack it in the parameter list, with defaults:
function formatLesson({ title, minutes = 15, level = 'Beginner' }) {
return `${title}: ${minutes} min, ${level}`;
}
console.log(formatLesson({ title: 'Closures', minutes: 20, level: 'Intermediate' }));
// → Closures: 20 min, Intermediate
console.log(formatLesson({ title: 'Variables' }));
// → Variables: 15 min, Beginner
Options objects make calls self-describing, and the order of properties does not matter. To allow calling with no argument at all, default the whole object too:
function createToast({ message = 'Saved', duration = 3000 } = {}) {
return `${message} for ${duration}ms`;
}
console.log(createToast()); // → Saved for 3000ms
Without = {}, createToast() would throw, because you cannot destructure undefined.
Spread with arrays
Three dots before an array expand it into individual values:
const beginner = ['HTML', 'CSS'];
const advanced = ['Accessibility', 'JavaScript'];
const all = [...beginner, ...advanced];
console.log(all); // → ['HTML', 'CSS', 'Accessibility', 'JavaScript']
const copy = [...beginner];
copy.push('Responsive');
console.log(beginner); // → ['HTML', 'CSS'] (unchanged)
console.log(Math.max(...[3, 9, 4])); // → 9
Spread works on any iterable, so [...'hey'] gives ['h', 'e', 'y'] and [...document.querySelectorAll('li')] turns a NodeList into an array.
Spread with objects
Spread in an object literal copies an object's own properties into a new object:
const defaults = { theme: 'light', fontSize: 16, motion: true };
const saved = { theme: 'dark' };
const settings = { ...defaults, ...saved };
console.log(settings); // → { theme: 'dark', fontSize: 16, motion: true }
When two objects have the same key, the later one wins. That is why defaults go first and overrides after. You can also override a single property while copying:
const updatedSettings = { ...settings, fontSize: 18 };
console.log(updatedSettings.fontSize); // → 18
console.log(settings.fontSize); // → 16
This "copy with a change" pattern is how you update state without mutating the original.
Spread makes a shallow copy. Nested objects and arrays are shared, not copied. Changing copy.settings.theme would also change the original. The next lesson covers deep copies with structuredClone.
Rest: collect the remainder
Rest uses the same three dots, but on the receiving side. It gathers leftover values into an array or object.
Rest parameters
function total(...prices) {
return prices.reduce((sum, price) => sum + price, 0);
}
console.log(total(4, 5.5, 10)); // → 19.5
console.log(total()); // → 0
prices is a real array. Combine fixed parameters with a rest parameter, which must come last:
function log(level, ...messages) {
console.log(`[${level}]`, messages.join(' '));
}
log('info', 'Saved', '3 items'); // → [info] Saved 3 items
Rest parameters replace the old arguments object, which is not a real array and does not exist in arrow functions.
Rest in destructuring
const [winner, ...others] = ['Ana', 'Ben', 'Cy'];
console.log(winner, others); // → Ana ['Ben', 'Cy']
const { password, ...safeUser } = { id: 7, name: 'Leo', password: 'hunter2' };
console.log(safeUser); // → { id: 7, name: 'Leo' }
Object rest is a neat way to drop a property before logging or sending an object, without changing the original.
Spread or rest?
The dots look identical. The position tells you which it is:
| Where the dots appear | Name | What happens |
|---|---|---|
| In a function call, array literal or object literal | Spread | Values are expanded out |
In a parameter list or on the left of = | Rest | Values are gathered in |
Summary
- Object destructuring unpacks by name; array destructuring unpacks by position.
- Use
:to rename and=for defaults that apply when a value isundefined. - Destructure options objects in parameters, and default the whole object with
= {}. - Spread expands arrays and objects into new ones; with objects, later keys win.
- Spread copies are shallow. Rest gathers remaining values into an array or object.