Пишем чистый код при помощи деструктуризации объектов в JavaScript
- среда, 30 марта 2022 г. в 00:38:40
Сравниваем традиционный способ извлечения значений и деструктуризацию (ES6) в JavaScript
В этой статье мы рассмотрим традиционное присваивание значений из объектов в переменные и новый синтаксис деструктуризации в ES6. Материал адаптирован на русский язык совместно с тимлидом группы frontend-разработки в Skillbox Иваном Казанцевым.
Деструктуризация — это синтаксис, который позволяет распаковывать значения из массивов или свойства из объектов в переменные.
Что нам это дает? Возможность писать более чистый и понятный код, экономя время и количество строк.
Сначала рассмотрим деструктуризацию объектов. И для примера возьмем объект - клиент (customer).
const customer = {
name: 'Sherlock',
email: 's.h.@gmail.com',
age: 34,
address: {
streetNo: '221b Baker Street',
city: 'London',
country: 'UK'
}
}
Если бы нам нужно было достать из него name и email, привычным способом мы бы сделали так:
const name = customer.name;
const email = customer['email']; // или так
console.log(name); // Sherlock
console.log(email); // s.h@gmaill.com
С помощью деструктуризации мы можем делать так:
const { name, email } = customer;
console.log(name); // Sherlock
console.log(email); // s.h@gmaill.com
Как минимум, мы уже не пишем два раза customer и чувствуем себя чуть-чуть лучше, так как можем добавить в резюме что-то про DRY.
Но если мы хотим записать customer.name
в переменную с другим именем, выходит, снова нужен традиционный способ? Нет, это мы тоже можем сделать:
const { name: customerName, email } = customer;
// обратите внимание, имя свойства из объекта customer находится слева
console.log(customerName); // Sherlock
Если мы хотим присвоить значения уже существующим переменным, делаем почти тоже самое, но добавляем ()
.
let name, email;
({ name, email } = customer);
console.log(name);
console.log(email);
Почему мы добавляем ()
?
{
в левой части считается блоком, а не литералом объекта. Если опустите ()
, вы получите сообщение об ошибке:
{ name, email } = customer;
^SyntaxError: Unexpected token '='
Итак, мы поняли, что это удобно, можем усложнять. Если хотим получить доступ к свойствам city
и country
, в традиционном способе нам нужно использовать цепочку обращений:
const name = customer.name;
const streetNo = customer.address.streetNo;
const city = customer['address']['city']; // или так
console.log(name); // Sherlock
console.log(streetNo); // 221b Baker Street
console.log(city); // London
Мы можем сделать то же самое, но короче, используя деструктуризацию:
const { name, address: { streetNo, city } } = customer;
console.log(name); // Sherlock
console.log(streetNo); // 221b Baker Street
console.log(city); // UK
Возможно, выглядит сложнее, но это дело привычки. И да, мы все еще можем записать свойства streetNo
и city
в переменные с другим названием.
Идем дальше. Теперь перед нами стоит задача: добавить married (женат/замужем) нашему объекту customer
. Возможные варианты ответа: “да” (yes) или “нет” (no). В случае, если не указан, присвоить значение “нет ответа” (N/A).
Без деструктуризации мы бы сделали так:
let married = customer.married;
console.log(married); // undefined
if (!married) {
married = 'N/A';
}
console.log(married); // N/A
Но с деструктуризацией мы можем объявлять значения по умолчанию, тем самым избавиться от условия. Фантастика?
const { name, married = 'N/A' } = customer;
console.log(name); // Sherlock
console.log(married); // N/A
Представим, что нам нужно достать только name
( например, чтобы присвоить ему значение по умолчанию), а все остальное записать “как есть” в другую переменную.
const { name = 'Спрятался в коробке', ...rest } = customer;
console.log(name); // Sherlock
console.log(rest);
// {
// email: 's.h@gmaill.com',
// age: null,
// address: { streetNo: '221b Baker Street', city: 'London', country: 'UK' }
// }
Обратите внимание, вместо rest
вы можете использовать любое другое название переменной, просто не забудьте поставить ...
и расположить это в конце.
Стоит иметь ввиду, чтоnull
деструктурировать нельзя, мы получим ошибку:
function getCustomer() {
return null;
}
let { name, email } = getCustomer();
// TypeError: Cannot destructure property name of 'undefined' or 'null'.
Поэтому мы должны обрабатывать такие случаи, например, так:
let { name = 'Спрятался в коробке', email = null } = getCustomer() || {};
console.log(name, email); // Спрятался в коробке null
Попробуем использовать деструктуризацию для упрощения работы с аргументами функции? Давайте представим, что нам нужна функция, которая выводит в консоль имя и город клиента.
Как бы мы сделали ранее:
let display = (customer) => console.log(`${customer.name} ${customer.address.city}`);
display(customer); // Sherlock London
Как мы сделаем теперь:
let display = ( { name, address: { city } } ) => console.log(`${name} ${city}`);
display(customer); // Sherlock London
Да, это работает и с массивами. Для примера нам понадобится пакет с фруктами.
const fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
Если бы нам нужно было достать банан и апельсин, ранее мы бы сделали следующее:
let firstFruit = fruits[0];
let secondFruit = fruits[1];
console.log(firstFruit); // Banana
console.log(secondFruit); // Orange
Но не сегодня, сегодня мы познакомились с деструктуризацией!
let [firstFruit, secondFruit, thirdFruit] = fruits;
console.log(firstFruit); // Banana
console.log(secondFruit); // Orange
console.log(secondFruit); // Apple (да, мы можем позволить себе и третий фрукт, потому что мы молодцы)
В объектах мы могли доставать любые значения свойств по имени и записывать их в переменные. А что, если мы хотим достать только первый и третий фрукт из массива? Нам просто нужно добавить лишнюю запятую.
let [firstFruit, , thirdFruit] = fruits;
Да-да, мы не указываем название переменной, и второй элемент пропускается.
И в массивах мы тоже можем использовать остаточные параметры. Например, мы хотим достать первый фрукт себе, второй оставить в пакете, а все остальное отдать друзьям:
let [yourFav, , ...friendsFav] = fruits;
console.log(yourFav); // Banana
console.log(friendsFav); // [ 'Apple', 'Mango' ]
И в конце — фокус. Сейчас мы поменяем местами первый и второй фрукт, не объявляя для этого новую переменную.
let [firstFruit, secondFruit] = fruits;
console.log(firstFruit); // Banana
console.log(secondFruit); // Orange
[firstFruit, secondFruit] = [secondFruit, firstFruit]
console.log(firstFruit); // Orange
console.log(secondFruit); // Banana
Ловкость деструктуризации и никакого мошенничества.
Ну а на сегодня все. Надеюсь, после этой статьи вам удастся упростить свой код и сделать его более читаемым.