Исчерпывающий гайд по деструктуризации и оператору ... (spread/rest - три точки, многоточие) в JavaScript
-
Главное: деструктуризация упрощает извлечение данных из объектов и массивов, а троеточие используется в двух разных ролях — spread «раскрывает» коллекции, а rest «собирает остатки». Освойте базовые шаблоны ниже — и получите удобную шпаргалку для повседневной разработки и собеседований.^1^3^5^7^9
Оглавление
- Что такое деструктуризация
- Деструктуризация массивов
- Деструктуризация объектов
- Глубокая (вложенная) деструктуризация
- Значения по умолчанию и вычисляемые значения
- Переименование переменных при деструктуризации
- Игнорирование элементов и «сбор остатка» с rest
- Деструктуризация в параметрах функций
- Типичные практики и частые ошибки
- Оператор …: spread vs rest
- Практические кейсы со spread
- Полезные паттерны для React/Node.js/TS
- Шпаргалка (Cheatsheet)
Что такое деструктуризация
Деструктурирующее присваивание — это синтаксис, позволяющий «распаковывать» элементы массива или свойства объекта в переменные напрямую, делая код короче и нагляднее.^2^7
Пример: const [a, b] = arr; или const {x, y} = obj; извлекают значения в переменные с одной строки вместо нескольких обращений по индексу/ключу.^4^2
Деструктуризация массивов
Простая распаковка:
const arr = [10, 20, 30]; const [first, second, third] = arr;Пропуск элементов:
const [x, , z] = [1, 2, 3]; // x=1, z=3Обмен значений без временной переменной:^2
let a = 1, b = 3; [a, b] = [b, a]; // a=3, b=1Значения по умолчанию:^7
const [a = 1, b = 2, c = 3] = [^10]; // a=10, b=2, c=3Остаток массива с rest:
const [head, ...tail] = [1, 2, 3, 4]; // head=1, tail=[2,3,4]Результаты split()/match():
const [firstName, lastName] = 'Ada Lovelace'.split(' '); // firstName='Ada'Возврат нескольких значений функцией:^2
function minmax(nums) { return [Math.min(...nums), Math.max(...nums)]; } const [min, max] = minmax([5,1,9]); // min=1, max=9
Деструктуризация объектов
Базовая распаковка:
const person = { name: 'Alice', age: 30 }; const { name, age } = person;Значения по умолчанию:
const { city = 'Unknown' } = {};Переименование переменных:
const user = { id: 42, isAdmin: true }; const { id: userId, isAdmin: admin } = user; // userId=42, admin=trueСбор «остатка» полей (object rest):^3
const obj = { a: 1, b: 2, c: 3 }; const { a, ...rest } = obj; // a=1, rest={ b:2, c:3 }Деструктуризация с вычисляемым именем ключа:
const key = 'score'; const stats = { score: 99, level: 3 }; const { [key]: currentScore } = stats; // currentScore=99
Глубокая (вложенная) деструктуризация
Извлечение из вложенных объектов:^11
const user = { name: 'John', contact: { email: 'john@ex.com', phones: { mobile: '123', work: '456' } }, roles: ['user', 'editor'] }; const { name, contact: { email, phones: { mobile } }, roles: [primaryRole] } = user; // name='John', email='john@ex.com', mobile='123', primaryRole='user'Смешанная с массивами:
const data = { items: [{ id: 1, tags: ['a','b'] }, { id: 2, tags: ['c'] }] }; const { items: [{ id: firstId, tags: [firstTag] }] } = data; // firstId=1, firstTag='a'Осторожно с отсутствующими ветками — используйте значения по умолчанию для безопасности:
const cfg = {}; const { server: { host = '127.0.0.1' } = {} } = cfg;
Значения по умолчанию и вычисляемые значения
Значения по умолчанию вычисляются лениво — выражение вызывается только если поле/элемент отсутствует:^7
function computeDefault() { console.log('called'); return 100; } const [x = computeDefault()] = []; // вызов произойдёт const [y = computeDefault()] = [^5]; // не вызовется
Переименование переменных при деструктуризации
Объекты:
const { name: fullName, age: years } = { name: 'M', age: 20 };Массивы переименовывают именами слева:
const [width: w, height: h] = ??? // так нельзя // Для массивов просто используйте нужные имена: const [w, h] = [800, 600];
Игнорирование элементов и «сбор остатка» с rest
Игнорирование:
const [ , second ] = [1,2,3]; // second=2Сбор остатка:
const [first, ...others] = [1,2,3,4]; // others=[2,3,4] const { a, ...restObj } = { a:1, b:2, c:3 }; // restObj={ b:2, c:3 }Rest всегда стоит последним и допускается только один rest.^9
Деструктуризация в параметрах функций
Массивы в параметрах:^12
function parseDate([year, month, day]) { return new Date(year, month - 1, day); } parseDate([2025, 12, 31]);Объекты в параметрах:
function createUser({ name, email, role = 'user' }) { return { name, email, role }; }Глубокая деструктуризация прямо в сигнатуре:
function handle({ meta: { id }, payload: { items: [first] = [] } = {} }) { return { id, first }; }С rest-параметрами:^13
function sum(label, ...nums) { console.log(label, nums.reduce((a,b)=>a+b,0)); } sum('total', 1,2,3); // nums=[1,2,3]
Типичные практики и частые ошибки
- Обмен значений без временной переменной с массивной деструктуризацией.^2
- Выборка нужных полей из ответа API, игнорируя всё остальное.
- Осторожно: «плоская» деструктуризация вложенных полей может кидать ошибку, если промежуточный объект undefined. Используйте значения по умолчанию для узлов: const { a: { b } = {} } = obj.
- Нельзя использовать объектную деструктуризацию слева без объявления без скобок:
// ({a} = someObj); // обернуть в скобки при присваивании существующим переменным- Rest-параметр должен быть последним и единственным rest.^9
- Не путать spread и rest: одинаковый синтаксис …, но разные контексты и смысл.^6
Оператор …: spread vs rest (в чём разница)
- Spread «раскрывает» итерируемые элементы или свойства объекта: передача массива как набора аргументов, копирование/слияние массивов и объектов.^14^15^6
- Rest «собирает остатки» в массив (в функциях) или объект (при объектной деструктуризации).^5^9
Примеры «как отличить»:^3
// spread: раскладывает Math.max(...[1,2,3]); // равно Math.max(1,2,3) // rest: собирает function f(a, ...rest) { /* rest это массив оставшихся аргументов */ }
Практические кейсы со spread
Передача массива как аргументов:^15
const nums = [1, 2, 3]; console.log(Math.max(...nums));Объединение массивов и вставка «посередине»:^14
const head = [1, 2]; const mid = [3, 4]; const tail = [^5]; const merged = [...head, ...mid, ...tail]; // [1,2,3,4,5]Клонирование массива/объекта (поверхностная копия):^6
const a1 = [1,2]; const a2 = [...a1]; const o1 = { x: 1, y: 2 }; const o2 = { ...o1 }; // поверхностноИммутабельные обновления:
const state = { user: { name: 'A', meta: { age: 30 } } }; // поверхностное обновление верхнего уровня: const next = { ...state, user: { ...state.user, name: 'B' } };Удаление поля при «копировании»:
const { password, ...publicUser } = user; // убрать чувствительное полеПреобразование строки в массив символов:^6
const chars = [...'Привет']; // ['П','р','и','в','е','т']Слияние объектов с приоритетом правых свойств:^17
const base = { role: 'user', active: true }; const patch = { role: 'admin' }; const result = { ...base, ...patch }; // role='admin'
Полезные паттерны для React/Node.js/TS
React props/state:
function Button({ kind = 'primary', ...props }) { return <button className={`btn btn-${kind}`} {...props} />; }Опциональные опции c дефолтами:
function connectDB({ host='127.0.0.1', port=5432, user, password } = {}) { /* ... */ }Сужение данных из сложных DTO:
const { id, profile: { email } = {} } = dto;TypeScript + деструктуризация:
- Явные типы переменных после деструктуризации:
const { id, name }: { id: number; name: string } = user;- Осторожно: деструктуризация не делает глубокого readonly и не меняет тип вложенных значений.
Шпаргалка (Cheatsheet)
- Массивы:
const [a, b] = arr const [first, , third] = arr const [head, ...tail] = arr [a, b] = [b, a] // swap const [x = 1] = []- Объекты:
const { x, y } = obj const { x: x1, y: y1 } = obj // переименование const { x = 0 } = obj // дефолт const { a, ...rest } = obj // остаток полей const { m: { n } = {} } = obj // безопасная вложенность- В функциях:
function f([x, y]) {} function g({ a, b = 2 }) {} function h(a, ...rest) {} // rest в конце- Spread:
fn(...args) const merged = [...a1, ...a2] const copy = { ...obj } const patch = { ...base, override: 1 }- Частые ошибки:
- Нельзя два rest-параметра и rest не в конце^9
- Поверхностное копирование (вложенные объекты всё еще по ссылке)
- Возможен TypeError при глубокой деструктуризации без дефолтов (читаете undefined.property)
- Для присваивания в уже объявленные переменные объектной деструктуризации используйте скобки: ({a} = src)
Расширенные примеры «на все случаи»
Глубокая деструктуризация массива объектов:
const list = [ { id: 1, meta: { tags: ['js','es6'] } }, { id: 2, meta: { tags: ['node'] } } ]; const [ { id: firstId, meta: { tags: [firstTag] = [] } = {} }, { id: secondId, meta: { tags: [, secondTag] = [] } = {} } ] = list; // firstId=1, firstTag='js', secondId=2, secondTag=undefinedДеструктуризация результата RegExp:
const [, year, month, day] = /^(\d{4})-(\d{2})-(\d{2})$/.exec('2025-10-27') || [];Выборка параметров запроса с дефолтами:
function listUsers(query={}) { const { page = 1, perPage = 20, filter: { role = 'all', active = true } = {} } = query; // ... }Нормализация вложенных ответов API:
const apiResp = { ok: true, data: { user: { id: 7, profile: { name: 'Ann' } } } }; const { data: { user: { id, profile: { name } = {} } = {} } = {} } = apiResp || {};Слияние конфигов без мутаций:^6
const defaults = { retry: 3, headers: { 'X': 1 } }; const userCfg = { headers: { 'Y': 2 } }; const cfg = { ...defaults, headers: { ...defaults.headers, ...userCfg.headers } };Оптимальная передача аргументов:
function callMax(arr) { return Math.max(...arr); }Клонирование без глубокого копирования:
const arr2 = [...arr1]; const obj2 = { ...obj1 }; // вложенные объекты/массивы остаются по ссылке
Важно помнить
- Деструктуризация ничего не «ломает» справа: она копирует значения в переменные, не изменяя исходную структуру.^1
- Spread/rest — синтаксис с троеточием, но смысл зависит от контекста:
- Для устойчивого к ошибкам кода используйте дефолты на промежуточных уровнях вложенности.
Дополнительные материалы
- MDN: Деструктурирующее присваивание и Spread syntax^2
- Современный учебник JavaScript ( learn.javascript.ru ) : деструктуризация и rest/spread^10^5
- Doka: Деструктуризация и Spread^4
- Хабр/Обучающие статьи по spread/rest^16^3
Все приёмы и определения согласованы со спецификой ES6+ и документацией MDN/learn.javascript.ru/Doka.^8^1^4^7^6
⁂ -
Как по мне, смое главное понять алгоримт действий, тогда что и куда подставить не будет такой проблемой. Круто, что есть люди, которые готовы разложить все по полочкам.
-
Всегда путаюсь с этой деструктуризацией. Вроде всё просто, но похоже не до конца всё понятно,поэтому есть траблы что к чему относится…
© 2024 - 2025 ExLends, Inc. Все права защищены.