JavaScript · Синтаксис · Промежуточный

Деструктуризация и spread

10 задач

Извлекайте значения из массивов и объектов в одной строке. Охватывает деструктурирующее присваивание, оператор spread и rest-параметры.

Деструктуризация массива и объекта: дефолты, вложенность, переименование

#
Деструктуризация позволяет извлекать значения из массивов и объектов в именованные переменные одним лаконичным выражением. **Деструктуризация массива** ```javascript const [a, b, c] = [1, 2, 3]; // a=1, b=2, c=3 // Пропустить элементы через пустые слоты const [first, , third] = [10, 20, 30]; // first=10, third=30 // Значения по умолчанию — используются когда значение undefined const [x = 0, y = 0] = [5]; // x=5, y=0 (y использует дефолт, т.к. array[1] — undefined) // Обменять две переменные без временной let m = 1, n = 2; [m, n] = [n, m]; // m=2, n=1 ``` **Деструктуризация объекта** ```javascript const { name, age } = { name: 'Alice', age: 30, role: 'admin' }; // name='Alice', age=30 (role игнорируется) // Переименовать при деструктуризации const { name: userName, age: userAge } = user; // userName='Alice', userAge=30 // Значения по умолчанию const { host = 'localhost', port = 3000 } = config; // Переименование + дефолт const { timeout: ms = 5000 } = options; ``` **Вложенная деструктуризация** ```javascript const { address: { city, zip } } = { name: 'Alice', address: { city: 'Kyiv', zip: '01001' }, }; // city='Kyiv', zip='01001' // Вложенный массив const [[a, b], [c, d]] = [[1, 2], [3, 4]]; ``` **Деструктуризация в параметрах функции** ```javascript // Вместо: function greet(user) { const { name, age } = user; ... } function greet({ name, age = 25 }) { return `${name} is ${age}`; } greet({ name: 'Bob' }); // 'Bob is 25' // С массивами: function first([head]) { return head; } first([10, 20, 30]); // 10 ``` **Распространённая ошибка: деструктуризация null/undefined** ```javascript const { name } = null; // TypeError: Cannot destructure property 'name' of null // Безопасно с дефолтом: const { name } = user ?? {}; ```

Rest-параметры, spread в массивах и объектах, ловушка поверхностной копии

#
**Rest в деструктуризации — собрать остаток** ```javascript // Rest массива const [head, ...tail] = [1, 2, 3, 4]; // head=1, tail=[2, 3, 4] // Rest объекта — собрать все не деструктурированные ключи const { name, ...rest } = { name: 'Alice', age: 30, role: 'admin' }; // name='Alice', rest={ age: 30, role: 'admin' } ``` **Rest в параметрах функции** ```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 оператор — развернуть итерируемый в отдельные элементы** ```javascript // Развернуть массив как аргументы функции Math.max(...[3, 1, 4, 1, 5]) // 5 // Объединить массивы 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] // Поверхностная копия const copy = [...a]; // [1, 2, 3] — новый массив ``` **Spread с объектами** ```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 } — последний побеждает // Слияние объектов const defaults = { color: 'red', size: 'M' }; const config = { size: 'L', weight: 'heavy' }; const merged = { ...defaults, ...config }; // { color: 'red', size: 'L', weight: 'heavy' } ``` **Spread — поверхностная копия: вложенные объекты всё ещё общие** ```javascript const original = { a: 1, nested: { b: 2 } }; const copy = { ...original }; copy.a = 99; // original.a всё ещё 1 - OK copy.nested.b = 99; // original.nested.b ТОЖЕ 99 - общая ссылка! // Глубокая копия: используй structuredClone() или JSON-roundtrip const deepCopy = structuredClone(original); ``` **Object.assign vs spread** `Object.assign(target, source)` мутирует `target`. Spread всегда создаёт новый объект. Предпочитай spread. ```javascript Object.assign({}, defaults, config) // то же, что { ...defaults, ...config } Object.assign(obj, patch) // мутирует obj на месте ```

Практические паттерны: обмен, minMax, omit, pick, слияние конфигураций

#
**Обменять две переменные** ```javascript let a = 1, b = 2; [a, b] = [b, a]; // a=2, b=1 ``` **minMax одной строкой** ```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 ``` **Удалить свойство из объекта (без мутации)** ```javascript function omit(obj, ...keys) { const keysToOmit = new Set(keys); return Object.fromEntries( Object.entries(obj).filter(([k]) => !keysToOmit.has(k)) ); } // Сокращённо через rest-деструктуризацию: const { password, ...safeUser } = user; // safeUser имеет всё кроме password ``` **Выбрать конкретные свойства** ```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 } ``` **Слияние дефолтов с конфигурацией пользователя** ```javascript const DEFAULT_CONFIG = { timeout: 3000, retries: 3, verbose: false }; function createClient(userConfig = {}) { const config = { ...DEFAULT_CONFIG, ...userConfig }; // значения пользователя перекрывают дефолты; отсутствующие используют дефолты return config; } createClient({ timeout: 5000 }); // { timeout: 5000, retries: 3, verbose: false } ``` **Spread с итерируемыми (не только массивами)** ```javascript // Развернуть Set в массив для дедупликации const unique = [...new Set([1, 2, 2, 3, 3])]; // [1, 2, 3] // Развернуть строку в символы const chars = [... 'hello']; // ['h', 'e', 'l', 'l', 'o'] // Развернуть записи Map const m = new Map([['a', 1], ['b', 2]]); const obj = Object.fromEntries([...m]); // { a: 1, b: 2 } ```
01

Деструктуризация массива

#

Напишите функцию, которая принимает массив из как минимум трёх элементов и возвращает объект со свойствами first, second и rest (массив оставшихся элементов). Используйте деструктуризацию массива.

function splitArray(arr) {

}

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

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

Деструктуризация объекта

#

Напишите функцию, которая принимает объект пользователя (со свойствами name, age и email) и возвращает строку-приветствие, используя только name и age. Используйте деструктуризацию объекта в параметрах функции.

function greetUser({ name, age }) {

}

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

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

Обмен переменных

#

Напишите функцию, которая принимает два значения и возвращает их в обменянном порядке. Используйте деструктуризацию массива для обмена в одну строку.

function swap(a, b) {

}

console.log(swap(1, 2));
console.log(swap("hello", "world"));
Решение
function swap(a, b) {
    [a, b] = [b, a];
    return [a, b];
}

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

Слияние объектов

#

Напишите функцию, которая принимает два объекта и возвращает новый объект, содержащий все свойства обоих. Если свойство есть в обоих, побеждает значение второго объекта. Используйте оператор spread.

function mergeObjects(obj1, obj2) {

}

console.log(mergeObjects({ a: 1, b: 2 }, { b: 3, c: 4 }));
Решение
function mergeObjects(obj1, obj2) {
    return { ...obj1, ...obj2 };
}

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

Клонирование и обновление

#

Напишите функцию, которая принимает объект пользователя и новое имя, и возвращает новый объект — копию пользователя с обновлённым именем. Не изменяйте оригинал. Используйте оператор spread.

function updateName(user, newName) {

}

const user = { name: "Alice", age: 30, role: "admin" };
const updated = updateName(user, "Bob");
console.log(user);
console.log(updated);
Решение
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

Значения по умолчанию в деструктуризации

#

Напишите функцию, которая принимает объект конфигурации и возвращает объект настроек с применёнными значениями по умолчанию: theme по умолчанию 'light', fontSize — 16, language — 'en'.

function applyDefaults(config) {

}

console.log(applyDefaults({ theme: 'dark' }));
console.log(applyDefaults({ fontSize: 20, language: 'uk' }));
Решение
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 в вызове функции

#

Напишите функцию, которая принимает массив чисел и возвращает наибольшее из них, используя Math.max() с оператором spread (Math.max не принимает массив напрямую).

function maxValue(numbers) {

}

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

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

Rest-параметры

#

Напишите функцию sum(...numbers), которая принимает любое количество аргументов и возвращает их сумму.

function sum(...numbers) {

}

console.log(sum(1, 2, 3));
console.log(sum(10, 20, 30, 40, 50));
Решение
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

Переименование при деструктуризации

#

Напишите функцию, которая принимает объект продукта (со свойствами 'name' и 'price') и возвращает новый объект с переименованными свойствами 'title' и 'cost'. Используйте деструктуризацию с переименованием.

function renameProduct(product) {

}

console.log(renameProduct({ name: "Widget", price: 9.99 }));
Решение
function renameProduct(product) {
    const { name: title, price: cost } = product;
    return { title, cost };
}

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

Объединение массивов без дубликатов

#

Напишите функцию, которая принимает два массива и возвращает новый массив со всеми уникальными значениями обоих по порядку (без дубликатов). Используйте spread и Set.

function uniqueMerge(arr1, arr2) {

}

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

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