Деструктуризация: значения из объектов и массивов
Как извлечь нужные значения, переименовать переменную и задать запасное значение.
On this page
Мы уже читали свойства через точку: event.name, event.price. Если несколько значений нужны отдельно, можно сохранить каждое в переменной:
const event = { name: "Кинопоказ", price: 300 };
const name = event.name;
const price = event.price;
console.log(name, price); // "Кинопоказ", 300Деструктуризация позволяет записать это короче. Справа находится объект, слева перечислены свойства, которые нужно прочитать:
const event = { name: "Кинопоказ", price: 300 };
const { name, price } = event;
console.log(name, price); // "Кинопоказ", 300Здесь создаются две переменные: name и price. Объект остаётся прежним. Выбирать все свойства необязательно: const { name } = event прочитает только название.
Фигурные скобки выполняют разные задачи. В const event = { ... } они создают объект, а в const { name } = event описывают, что из него прочитать. Смотрите на их место в записи, а не только на форму.
Свойство и переменная могут называться по-разному
Допустим, переменная name уже занята. Извлечём то же свойство под именем eventName:
const event = { name: "Кинопоказ", price: 300 };
const { name: eventName, price } = event;
console.log(eventName); // "Кинопоказ"
console.log(price); // 300Запись name: eventName читается так: «возьми свойство name и запиши его в переменную eventName». Переменная name в этой строке не создаётся. Свойство объекта тоже не переименовывается: в event всё ещё находится name.
В обычном объекте двоеточие связывает ключ и значение. Здесь оно связывает имя исходного свойства и имя новой переменной.
Если свойства нет
Чтение отсутствующего свойства даёт undefined. Можно задать значение по умолчанию:
const event = { name: "Лекция" };
const { name, price = 0 } = event;
console.log(name, price); // "Лекция", 0
console.log(event.price); // undefined: в объект ничего не добавили.Значение после = подставляется, только если прочитано undefined. Это бывает при отсутствии свойства или при его явном значении undefined. Число 0, пустая строка и null сохраняются.
Переключите исходные данные и сравните обычную запись с деструктуризацией. В примере одновременно используются переименование и значение по умолчанию:
const event = { name: "Кинопоказ", price: 300 };
const { name: eventName, price = 0 } = event;
console.log(eventName, price);Результат обеих записей
"Кинопоказ", 300
Цена присутствует. Даже число 0 сохраняется как значение свойства.
Из массива берём по позиции
У объекта выбираем значения по именам свойств. У массива – по порядку элементов, поэтому слева нужны квадратные скобки:
const coordinates = [120, 80];
const [x, y] = coordinates;
console.log(x); // 120: первый элемент.
console.log(y); // 80: второй элемент.Имена x и y мы выбрали сами. Запись const [horizontal, vertical] = coordinates прочитает те же значения. Поменять имена местами – не значит поменять данные: const [y, x] = coordinates запишет первое число в y, второе в x.
Позицию можно пропустить, а для отсутствующего элемента – задать запасное значение:
const route = ["Москва", "Тверь"];
const [, destination, nextStop = "Конечная"] = route;
console.log(destination); // "Тверь"
console.log(nextStop); // "Конечная"Запятая перед destination пропускает первый элемент. Третьего элемента нет, поэтому применяется значение по умолчанию. Как и у объекта, оно подставляется для undefined, но не для null.
| Источник | Запись | Как выбираются значения |
|---|---|---|
| Объект | const { name, price } = event | По именам свойств; их порядок в записи не важен |
| Массив | const [x, y] = coordinates | По позиции; порядок важен |
В параметрах функции
Функция может получить целый объект и сразу извлечь нужные свойства. Сравните две самостоятельные записи одной функции:
function formatEvent(event) {
return `${event.name}: ${event.price} ₽`;
}
console.log(formatEvent({ name: "Кинопоказ", price: 300 }));
// "Кинопоказ: 300 ₽"function formatEvent({ name, price }) {
return `${name}: ${price} ₽`;
}
console.log(formatEvent({ name: "Кинопоказ", price: 300 }));
// "Кинопоказ: 300 ₽"В обеих версиях один параметр – объект. Скобки { name, price } извлекают его свойства при вызове. Поэтому formatEvent("Кинопоказ", 300) не заменяет вызов с объектом: это другие входные данные.
В следующем разделе TypeScript сможет описать форму этого объекта. Позже в React похожая запись извлечёт параметры компонента. Это уже знакомый синтаксис JavaScript, а не отдельное правило React.
Деструктуризация не делает копию объекта
Если свойство содержит вложенный объект, новая переменная ссылается на него же:
const event = { venue: { city: "Москва" } };
const { venue } = event;
venue.city = "Тверь";
console.log(event.venue.city); // "Тверь"Это то же поведение ссылок, которое мы разбирали в статье об объектах. Деструктуризация только читает значение свойства. Она не создаёт независимую копию вложенных данных.
С числом ситуация другая: после const { price } = event переменная содержит прочитанное число. Последующее изменение event.price само по себе не обновит price.
Дополнительно: собрать оставшиеся значения
Три точки слева от = собирают остаток (rest). У массива получается новый массив оставшихся элементов:
const names = ["Кинопоказ", "Лекция", "Концерт"];
const [first, ...others] = names;
console.log(first); // "Кинопоказ"
console.log(others); // ["Лекция", "Концерт"]В таком обычном объекте rest собирает свойства, которые мы не выбрали отдельно. Здесь id попадёт в свою переменную, а name и price – в новый объект details:
const event = { id: 1, name: "Лекция", price: 0 };
const { id, ...details } = event;
console.log(id); // 1
console.log(details); // { name: "Лекция", price: 0 }Остаток записывают последним. Сами исходные данные не меняются, вложенные объекты по-прежнему не копируются глубоко.
В записи { ...event } три точки раскладывают свойства в новый объект – это spread. В const { id, ...details } = event они собирают оставшиеся свойства – это rest. Внешне похоже, но направление действия разное.
Попробуйте сами
- Создайте мероприятие с
name,priceиvenue. Извлеките название вeventName, а цену – вprice. - Задайте запасную цену
0. Проверьте объект без цены, с ценой0и с ценойnull. Объясните разницу. - Напишите
formatEvent({ name, price }), которая возвращает подпись. Вызовите её с двумя разными объектами. - Из массива
["Москва", "Тверь", "Санкт-Петербург"]получите первый город и массив остальных. Исходный массив должен остаться прежним.
Для каждого шага покажите результат через console.log. Если короткая запись сложна, сначала напишите обращения через точку или индекс, затем сократите их.
Далее разнесём код по файлам: модули, import и export. Справочник: деструктуризация на MDN.