Деструктуризация в JavaScript #
Деструктуризация — синтаксис извлечения полей из объекта или элементов из массива в отдельные переменные за одно присваивание. Она сокращает шаблонный код в обработчиках заказов, ответах API и параметрах функций, не меняя исходные данные (если вы не переназначаете сами поля).
Деструктуризация массива #
const pair = ['express', 399]
const [type, fee] = pair
// type === 'express', fee === 399
Пропуск элементов:
const rgb = [255, 120, 64]
const [r, , b] = rgb
// r === 255, b === 64
Обмен без временной переменной:
let a = 1
let b = 2
;[a, b] = [b, a]
// a === 2, b === 1
Значения по умолчанию (массив) #
const coords = [10]
const [x = 0, y = 0] = coords
// x === 10, y === 0
Если элемент undefined, подставится значение по умолчанию; если элемент отсутствует в разреженном массиве — тоже.
Rest в массиве #
const queue = ['priority', 'order-1', 'order-2', 'order-3']
const [head, ...rest] = queue
// head === 'priority', rest === ['order-1', 'order-2', 'order-3']
rest должен быть последним в списке слева.
Деструктуризация объекта #
const line = { sku: 'kb-01', price: 4900, qty: 2 }
const { sku, qty } = line
// sku === 'kb-01', qty === 2
Имя переменной совпадает с ключом. Другое имя — через псевдоним:
const { sku: productCode, price: unitPrice } = line
// productCode === 'kb-01', unitPrice === 4900
Значения по умолчанию (объект) #
const delivery = { zone: 'center' }
const { zone, fee = 199, express = false } = delivery
// zone === 'center', fee === 199, express === false
По умолчанию срабатывает при undefined, не при null:
const { note = 'без комментария' } = { note: null }
// note === null
Rest в объекте #
const checkout = {
orderId: 'ord-42',
total: 5199,
currency: 'RUB',
paid: true,
}
const { orderId, ...meta } = checkout
// orderId === 'ord-42'
// meta === { total: 5199, currency: 'RUB', paid: true }
Удобно отделить идентификатор от остального payload при логировании.
Вложенная деструктуризация #
const response = {
data: {
cart: {
lines: [{ sku: 'ms-02', qty: 1 }],
},
},
}
const {
data: {
cart: { lines },
},
} = response
lines[0].sku // "ms-02"
Глубокие цепочки ухудшают читаемость — на 2–3 уровня обычно достаточно; дальше вынесите промежуточную переменную.
Деструктуризация в параметрах функции #
function formatLine({ sku, qty, price = 0 }) {
return `${sku} × ${qty} = ${price * qty} ₽`
}
formatLine({ sku: 'hp-09', qty: 2, price: 890 })
// "hp-09 × 2 = 1780 ₽"
Значения по умолчанию для всего объекта:
function printEta({ minutes = 30, unit = 'мин' } = {}) {
return `~${minutes} ${unit}`
}
printEta() // "~30 мин"
printEta({ minutes: 12 }) // "~12 мин"
= {} защищает от вызова без аргумента.
Rest в параметрах #
function sumScores(first, second, ...rest) {
return [first, second, ...rest].reduce((s, n) => s + n, 0)
}
sumScores(10, 20, 5, 5) // 40
Связь с Функции: rest собирает «хвост» аргументов в массив.
Деструктуризация при присваивании #
let track = { id: 't1', title: 'Focus' }
;({ id, title } = track)
// скобки обязательны: без них { воспринимается как блок
В const/let скобки не нужны:
const { title } = track
Итерация entries с деструктуризацией #
const fees = new Map([
['standard', 199],
['express', 399],
])
for (const [kind, amount] of fees) {
console.log(kind, amount)
}
Object.entries({ a: 1, b: 2 }).forEach(([key, value]) => {
console.log(key, value)
})
Практика: разбор ответа доставки #
function normalizeDelivery(apiRow) {
const {
id,
status,
address: { city, street, flat } = {},
eta_minutes: eta = null,
} = apiRow
return {
id,
status,
city: city ?? '',
street: street ?? '',
flat: flat ?? '',
eta,
}
}
normalizeDelivery({
id: 'd-7',
status: 'en_route',
address: { city: 'Москва', street: 'Пример, 5' },
eta_minutes: 14,
})
Вложенный { city, street, flat } = {} не упадёт, если address отсутствует.
Практика: чекаут и плейлист #
function checkoutTotals({ lines, promo = 0, deliveryFee = 0 }) {
const subtotal = lines.reduce((s, { price, qty }) => s + price * qty, 0)
const total = Math.max(0, subtotal - promo + deliveryFee)
return { subtotal, total }
}
checkoutTotals({
lines: [
{ price: 1000, qty: 2 },
{ price: 500, qty: 1 },
],
promo: 200,
deliveryFee: 199,
})
// { subtotal: 2500, total: 2499 }
const [, second, ...others] = ['Intro', 'Main', 'Outro', 'Bonus']
// second === 'Main', others === ['Outro', 'Bonus']
Осторожно: мутация вложенных ссылок #
Деструктуризация копирует ссылки, не глубокие клоны:
const cart = [{ sku: 'a', qty: 1 }]
const [first] = cart
first.qty = 5
cart[0].qty // 5
Для иммутабельного обновления строки корзины используйте spread на уровне объекта (см. Методы массивов).
Итог #
- Массивы:
[a, b] = arr, пропуск, значения по умолчанию,...rest. - Объекты:
{ field, other: alias } = obj, значения по умолчанию,...restдля «всего кроме». - Параметры функций с деструктуризацией делают API явным;
= {}защищает отundefined. - Вложенность удобна для JSON, но не злоупотребляйте глубиной.
- Деструктуризация не клонирует вложенные объекты автоматически.