Menu
Русский

Деструктуризация в JavaScript: объекты, массивы, rest

Разбираемся, как работает деструктуризация в JavaScript: достаём значения из объектов и массивов, переименовываем, задаём значения по умолчанию, работаем с вложенностью и параметрами функций.

Деструктуризация в JavaScript — это сопоставление по форме

Деструктуризация javascript позволяет написать шаблон, повторяющий форму объекта или массива, и одной строкой вытащить значения по имени или по позиции. Вместо того чтобы вручную лезть в значение свойство за свойством, вы просто описываете, что хотите получить, — а JavaScript сам всё отдаёт.

Есть два варианта:

index.js
Output
Click Run to see the output here.

Фигурные скобки сопоставляются с объектом по именам свойств, а квадратные — с массивом по позициям. И в том, и в другом случае переменные до знака = — это новые объявления: вы не обращаетесь к значению по индексу, а описываете шаблон, по которому из него вытаскиваются нужные куски.

До появления деструктуризации тот же самый код выглядел так:

const name = user.name;
const age = user.age;
const first = scores[0];
const second = scores[1];

Не катастрофа, конечно, но когда пишешь такое в каждой функции — быстро надоедает.

Деструктуризация объекта в JS идёт по именам свойств

Для объектов имена в фигурных скобках должны совпадать с именами свойств исходного объекта. Порядок не важен — JavaScript ищет значения по ключу.

index.js
Output
Click Run to see the output here.

Если свойство в объекте отсутствует, переменная просто окажется undefined — никакой ошибки не будет:

index.js
Output
Click Run to see the output here.

Именно это тихое undefined стоит держать в голове, когда опечатка в имени свойства заставляет вас в два часа ночи чесать затылок.

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

Иногда имя свойства в объекте — совсем не то, как вы хотите назвать переменную. Может, оно конфликтует с чем-то в текущей области видимости, а может, API использует соглашение об именовании, которое вам не по душе. В таких случаях используйте синтаксис оригинал: новоеИмя, чтобы переименовать переменную при деструктуризации:

index.js
Output
Click Run to see the output here.

Читается это так: «возьми свойство id и назови его userId». Сначала идёт имя свойства, потом — через двоеточие — новое имя переменной. Внешне похоже на аннотацию типов из других языков, но это не она.

Значения по умолчанию

Если свойства может не оказаться, задайте значение по умолчанию прямо в шаблоне деструктуризации:

index.js
Output
Click Run to see the output here.

Значения по умолчанию срабатывают только тогда, когда значение равно undefined. А вот null, 0 и "" проходят как есть, без подмены:

index.js
Output
Click Run to see the output here.

Вот на этом многие спотыкаются. Если хочешь, чтобы null тоже подхватывал значение по умолчанию, придётся делать явную проверку — либо уже после деструктуризации использовать оператор нулевого слияния ??.

Значения по умолчанию можно совмещать с переименованием:

index.js
Output
Click Run to see the output here.

Деструктуризация массива: всё решает позиция

У массивов нет имён — только индексы, поэтому шаблон сопоставляется по позиции. Если какие-то элементы не нужны, просто пропускай их через запятую:

index.js
Output
Click Run to see the output here.

Две запятые в начале означают «пропусти элементы с индексами 0 и 1». Выглядит, конечно, не самым очевидным образом, зато удобно, когда из середины массива нужно выдернуть только одно значение.

Деструктуризация массива особенно хороша с функциями, которые возвращают кортежи:

index.js
Output
Click Run to see the output here.

Тот же приём встречается повсюду в React-хуках: const [count, setCount] = useState(0).

Rest-паттерны: собираем «хвост»

Внутри паттерна деструктуризации ...имя собирает всё, что не было сопоставлено по имени или позиции, в новую переменную.

В массивах rest забирает хвост:

index.js
Output
Click Run to see the output here.

Применительно к объектам rest-оператор забирает все свойства, которые не были указаны явно:

index.js
Output
Click Run to see the output here.

Так принято «отрезать» одно поле от объекта, не мутируя его: в rest попадает новый объект со всеми полями, кроме id.

Важно: rest должен идти последним в шаблоне. Запись const [...init, last] — это синтаксическая ошибка.

Вложенная деструктуризация

Шаблоны можно вкладывать друг в друга. Если свойство — это сам объект или массив, его можно разобрать прямо в том же выражении:

index.js
Output
Click Run to see the output here.

Штука мощная, но злоупотреблять не стоит. Когда появляется третий уровень вложенных фигурных скобок, код превращается в ребус. В таких случаях лучше вытащить промежуточные значения в отдельные переменные — читаемость важнее «умности».

Момент, на котором часто спотыкаются: запись data: { user } в шаблоне не создаёт переменную data. Это указание «зайди внутрь data и продолжай деструктурировать там». Если нужен сам data, допишите его отдельно:

index.js
Output
Click Run to see the output here.

Деструктуризация параметров функции

Чаще всего деструктуризацию применяют именно в списке параметров функции. Благодаря этому «передача объекта с настройками» превращается в сигнатуру, которая сама себя документирует:

index.js
Output
Click Run to see the output here.

На стороне вызова это выглядит как обычный вызов с объектом опций. А внутри функции мы сразу получаем именованные переменные со значениями по умолчанию — и больше никакой мороки с options.name || "default".

Есть, правда, один подводный камень: если вызвать такую функцию без аргументов, будет ошибка — undefined деструктурировать нельзя. Поэтому задайте значение по умолчанию для всего параметра целиком:

index.js
Output
Click Run to see the output here.

= {} после паттерна значит «если аргумент не передали — считаем, что это пустой объект». А дальше в дело вступают дефолты изнутри.

Обмен значений и переприсваивание

Деструктуризация работает и с уже объявленными переменными — только объектный паттерн придётся обернуть в скобки (иначе JavaScript решит, что { открывает блок кода):

index.js
Output
Click Run to see the output here.

Обмен значений в массиве выглядит красиво. С объектами такое встречается реже, но приём со скобками стоит запомнить — пригодится.

Реальный пример

Соберём почти всё, что разобрали выше, в одном месте — функции, которая обрабатывает ответ от API:

index.js
Output
Click Run to see the output here.

У каждого уровня деструктуризации есть значение по умолчанию, поэтому функция спокойно переживает неполные данные — без кучи проверок if. В этом и весь смысл: сигнатура получается одновременно точной и снисходительной к входу.

Дальше: spread для объектов

Деструктуризация достаёт значения из объектов. Spread, наоборот, их кладёт — копирует, объединяет и переопределяет. В современном JavaScript эти две штуки ходят рука об руку, и следующим на очереди как раз spread.

Часто задаваемые вопросы

Что такое деструктуризация в JavaScript?

Деструктуризация — это синтаксис, который позволяет одной строкой достать значения из объекта или массива и сразу привязать их к переменным. Например, const { name } = user; вытащит свойство name из user, а const [first, second] = list; заберёт первые два элемента массива list. По сути, слева от = вы пишете шаблон, повторяющий форму того, что стоит справа.

Как переименовать переменную при деструктуризации?

Для этого есть синтаксис { исходноеИмя: новоеИмя }. Запись const { name: username } = user; берёт свойство name из объекта user и кладёт его в локальную переменную username. Многие путают это с аннотацией типа — запомните: сначала идёт имя свойства, а после двоеточия — имя новой переменной.

Можно ли задать значения по умолчанию при деструктуризации?

Да, и это одна из самых удобных фишек. const { timeout = 5000 } = options; подставит 5000, если options.timeout равно undefined. Важный момент: значение по умолчанию срабатывает только для undefinednull, 0 и '' пройдут как есть. Значения по умолчанию спокойно комбинируются с переименованием: const { t: timeout = 5000 } = options;.

Чем деструктуризация отличается от spread-оператора?

Синтаксис похож, но действия противоположные. Деструктуризация (const { a, b } = obj) достаёт значения из структуры, а spread (const copy = { ...obj }) наоборот — раскладывает их в новую структуру. А вот ... внутри шаблона деструктуризации — это уже rest-паттерн, он собирает всё оставшееся в отдельную переменную.

Учитесь программировать с Coddy

НАЧАТЬ