JavaScript · Syntax · Intermediate

Destructuring and spread

10 tasks

Extract values from arrays and objects in one line. Covers destructuring assignment, spread operator, and rest parameters.

Array and object destructuring: defaults, nesting, renaming

#
Destructuring lets you extract values from arrays and objects into named variables in one concise statement. **Array destructuring** ```javascript const [a, b, c] = [1, 2, 3]; // a=1, b=2, c=3 // Skip elements with empty slots const [first, , third] = [10, 20, 30]; // first=10, third=30 // Default values — used when the value is undefined const [x = 0, y = 0] = [5]; // x=5, y=0 (y uses default because array[1] is undefined) // Swap two variables without a temp let m = 1, n = 2; [m, n] = [n, m]; // m=2, n=1 ``` **Object destructuring** ```javascript const { name, age } = { name: 'Alice', age: 30, role: 'admin' }; // name='Alice', age=30 (role is ignored) // Rename while destructuring const { name: userName, age: userAge } = user; // userName='Alice', userAge=30 // Default values const { host = 'localhost', port = 3000 } = config; // host and port use defaults if missing from config // Rename + default const { timeout: ms = 5000 } = options; ``` **Nested destructuring** ```javascript const { address: { city, zip } } = { name: 'Alice', address: { city: 'Kyiv', zip: '01001' }, }; // city='Kyiv', zip='01001' // Nested array const [[a, b], [c, d]] = [[1, 2], [3, 4]]; ``` **Destructuring in function parameters** ```javascript // Instead of: function greet(user) { const { name, age } = user; ... } function greet({ name, age = 25 }) { return `${name} is ${age}`; } greet({ name: 'Bob' }); // 'Bob is 25' // With arrays: function first([head]) { return head; } first([10, 20, 30]); // 10 ``` **Common mistake: destructuring null/undefined** ```javascript const { name } = null; // TypeError: Cannot destructure property 'name' of null // Safe with default: const { name } = user ?? {}; ```

Rest parameters, spread in arrays and objects, shallow copy gotcha

#
**Rest in destructuring — collect the remainder** ```javascript // Array rest const [head, ...tail] = [1, 2, 3, 4]; // head=1, tail=[2, 3, 4] // Object rest — collect all non-destructured keys const { name, ...rest } = { name: 'Alice', age: 30, role: 'admin' }; // name='Alice', rest={ age: 30, role: 'admin' } ``` **Rest in function parameters** ```javascript function sum(...nums) { return nums.reduce((a, b) => a + b, 0); } sum(1, 2, 3, 4); // 10 function log(level, ...messages) { messages.forEach(m => console.log(`[${level}]`, m)); } log('INFO', 'starting', 'ready'); // [INFO] starting [INFO] ready ``` **Spread operator — expand iterable into individual items** ```javascript // Spread array into function arguments Math.max(...[3, 1, 4, 1, 5]) // 5 // Combine arrays const a = [1, 2, 3]; const b = [4, 5, 6]; const c = [...a, ...b]; // [1, 2, 3, 4, 5, 6] const d = [0, ...a, 99]; // [0, 1, 2, 3, 99] // Shallow copy const copy = [...a]; // [1, 2, 3] — new array ``` **Spread with objects** ```javascript const base = { x: 1, y: 2 }; const extended = { ...base, z: 3 }; // { x: 1, y: 2, z: 3 } const overridden = { ...base, x: 99 }; // { x: 99, y: 2 } — last wins // Merge objects const defaults = { color: 'red', size: 'M' }; const config = { size: 'L', weight: 'heavy' }; const merged = { ...defaults, ...config }; // { color: 'red', size: 'L', weight: 'heavy' } ``` **Spread is a shallow copy — nested objects are still shared** ```javascript const original = { a: 1, nested: { b: 2 } }; const copy = { ...original }; copy.a = 99; // original.a is still 1 - OK copy.nested.b = 99; // original.nested.b is ALSO 99 - shared reference! // Deep clone: use structuredClone() or JSON roundtrip for plain data const deepCopy = structuredClone(original); ``` **Object.assign vs spread** `Object.assign(target, source)` mutates `target`. Spread always creates a new object. Prefer spread. ```javascript Object.assign({}, defaults, config) // same as { ...defaults, ...config } Object.assign(obj, patch) // mutates obj in place ```

Practical patterns: swap, minMax, omit, pick, config merging

#
**Swap two variables** ```javascript let a = 1, b = 2; [a, b] = [b, a]; // a=2, b=1 ``` **minMax in one line** ```javascript function minMax(arr) { return [Math.min(...arr), Math.max(...arr)]; } const [min, max] = minMax([3, 1, 4, 1, 5, 9]); // min=1, max=9 ``` **Omit a property from an object (without mutation)** ```javascript function omit(obj, ...keys) { const keysToOmit = new Set(keys); return Object.fromEntries( Object.entries(obj).filter(([k]) => !keysToOmit.has(k)) ); } // Shorthand with rest destructuring: const { password, ...safeUser } = user; // safeUser has everything except password ``` **Pick specific properties** ```javascript function pick(obj, ...keys) { return Object.fromEntries(keys.map(k => [k, obj[k]])); } pick({ a: 1, b: 2, c: 3 }, 'a', 'c'); // { a: 1, c: 3 } ``` **Merge defaults with user config** ```javascript const DEFAULT_CONFIG = { timeout: 3000, retries: 3, verbose: false }; function createClient(userConfig = {}) { const config = { ...DEFAULT_CONFIG, ...userConfig }; // user values override defaults; missing ones use defaults return config; } createClient({ timeout: 5000 }); // { timeout: 5000, retries: 3, verbose: false } ``` **Spread with iterables (not just arrays)** ```javascript // Spread a Set into an array to deduplicate const unique = [...new Set([1, 2, 2, 3, 3])]; // [1, 2, 3] // Spread a string into chars const chars = [... 'hello']; // ['h', 'e', 'l', 'l', 'o'] // Spread a Map's entries const m = new Map([['a', 1], ['b', 2]]); const obj = Object.fromEntries([...m]); // { a: 1, b: 2 } ```
01

Array destructuring

#

Write a function that takes an array of at least three elements and returns an object with properties first, second, and rest (an array of the remaining elements). Use array destructuring.

function splitArray(arr) {

}

console.log(splitArray([1, 2, 3, 4, 5]));
Solution
function splitArray(arr) {
    const [first, second, ...rest] = arr;
    return { first, second, rest };
}

console.log(splitArray([1, 2, 3, 4, 5]));
02

Object destructuring

#

Write a function that takes a user object (with name, age, and email properties) and returns a greeting string using only the name and age. Use object destructuring in the function parameters.

function greetUser({ name, age }) {

}

console.log(greetUser({ name: "Alice", age: 30, email: "[email protected]" }));
Solution
function greetUser({ name, age }) {
    return `Hello, ${name}! You are ${age} years old.`;
}

console.log(greetUser({ name: "Alice", age: 30, email: "[email protected]" }));
03

Swap variables

#

Write a function that takes two values and returns them in swapped order. Use array destructuring to perform the swap in one line.

function swap(a, b) {

}

console.log(swap(1, 2));
console.log(swap("hello", "world"));
Solution
function swap(a, b) {
    [a, b] = [b, a];
    return [a, b];
}

console.log(swap(1, 2));
console.log(swap("hello", "world"));
04

Merge objects

#

Write a function that takes two objects and returns a new object that contains all properties from both. If a property exists in both, the second object's value should win. Use the spread operator.

function mergeObjects(obj1, obj2) {

}

console.log(mergeObjects({ a: 1, b: 2 }, { b: 3, c: 4 }));
Solution
function mergeObjects(obj1, obj2) {
    return { ...obj1, ...obj2 };
}

console.log(mergeObjects({ a: 1, b: 2 }, { b: 3, c: 4 }));
05

Clone and update

#

Write a function that takes a user object and a new name, and returns a new object that is a copy of the user with the name updated. Do not modify the original. Use the spread operator.

function updateName(user, newName) {

}

const user = { name: "Alice", age: 30, role: "admin" };
const updated = updateName(user, "Bob");
console.log(user);
console.log(updated);
Solution
function updateName(user, newName) {
    return { ...user, name: newName };
}

const user = { name: "Alice", age: 30, role: "admin" };
const updated = updateName(user, "Bob");
console.log(user);
console.log(updated);
06

Default values in destructuring

#

Write a function that takes a config object and returns a settings object with defaults applied. Use destructuring with default values: theme defaults to 'light', fontSize to 16, and language to 'en'.

function applyDefaults(config) {

}

console.log(applyDefaults({ theme: 'dark' }));
console.log(applyDefaults({ fontSize: 20, language: 'uk' }));
Solution
function applyDefaults({ theme = 'light', fontSize = 16, language = 'en' } = {}) {
    return { theme, fontSize, language };
}

console.log(applyDefaults({ theme: 'dark' }));
console.log(applyDefaults({ fontSize: 20, language: 'uk' }));
07

Spread into function call

#

Write a function that takes an array of numbers and returns the largest one, using Math.max() with the spread operator (Math.max does not accept an array directly).

function maxValue(numbers) {

}

console.log(maxValue([3, 1, 4, 1, 5, 9, 2, 6]));
Solution
function maxValue(numbers) {
    return Math.max(...numbers);
}

console.log(maxValue([3, 1, 4, 1, 5, 9, 2, 6]));
08

Rest parameters

#

Write a function sum(...numbers) that accepts any number of arguments and returns their sum.

function sum(...numbers) {

}

console.log(sum(1, 2, 3));
console.log(sum(10, 20, 30, 40, 50));
Solution
function sum(...numbers) {
    return numbers.reduce((acc, n) => acc + n, 0);
}

console.log(sum(1, 2, 3));
console.log(sum(10, 20, 30, 40, 50));
09

Rename on destructure

#

Write a function that takes a product object (with 'name' and 'price' properties) and returns a new object with the properties renamed to 'title' and 'cost'. Use destructuring with renaming.

function renameProduct(product) {

}

console.log(renameProduct({ name: "Widget", price: 9.99 }));
Solution
function renameProduct(product) {
    const { name: title, price: cost } = product;
    return { title, cost };
}

console.log(renameProduct({ name: "Widget", price: 9.99 }));
10

Combine arrays without duplicates

#

Write a function that takes two arrays and returns a new array containing all unique values from both, in order (no duplicates). Use spread and Set.

function uniqueMerge(arr1, arr2) {

}

console.log(uniqueMerge([1, 2, 3, 4], [3, 4, 5, 6]));
Solution
function uniqueMerge(arr1, arr2) {
    return [...new Set([...arr1, ...arr2])];
}

console.log(uniqueMerge([1, 2, 3, 4], [3, 4, 5, 6]));