Как стать автором
Обновить
887.97
OTUS
Цифровые навыки от ведущих экспертов

Деструктуризация массивов и объектов в JavaScript — в чем разница?

Время на прочтение15 мин
Количество просмотров42K
Автор оригинала: Oluwatobi Sofela

Деструктурирующее присваивание в JavaScript — это изящный способ извлечения значений из массивов и объектов, при котором в полной мере реализуется принцип DRY (англ. Don’t repeat yourself — «Не повторяйся»).

Цель этой статьи — продемонстрировать, как именно работают деструктурирующие присваивания массивов и объектов в JavaScript.

Поэтому без лишних слов предлагаю приступить к деструктуризации массивов.

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

Деструктуризация массива (англ. array destructuring) — это особый синтаксис, позволяющий извлекать значения из массива и записывать их в новые переменные с минимумом кода.

Например, без использования синтаксиса деструктуризации массива значение элемента массива копируется в новую переменную следующим образом:

const profile = ["Oluwatobi", "Sofela", "codesweetly.com"];

const firstName = profile[0];
const lastName = profile[1];
const website = profile[2];

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

Обратите внимание, что в приведенном выше фрагменте много повторяющегося кода, что не удовлетворяет принципу DRY.

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

const profile = ["Oluwatobi", "Sofela", "codesweetly.com"];

const [firstName, lastName, website] = profile;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

Посмотрите, как мы, словно по волшебству, очистили наш код, поместив три новые переменные (то есть firstName, lastName и website) в объект, являющийся массивом ([...]). Затем мы присвоили ему значения массива profile.

Другими словами, мы сказали компьютеру, чтобы тот извлек значения из массива profile и записал их в переменные, указанные слева от оператора присваивания.

В результате JavaScript парсит массив profile и копирует его первое значение ("Oluwatobi") в первую переменную деструктурирующего массива (firstName).

Аналогичным образом компьютер извлекает второе значение ("Sofela") из массива profile во вторую переменную (lastName) деструктурирующего массива.

Наконец, JavaScript копирует третье значение из массива profile ("codesweetly.com") в третью переменную (website) деструктурирующего массива.

Обратите внимание, что в приведенном выше коде массив profile деструктурируется путем ссылки на него. Однако деструктуризацию массива можно делать и напрямую. Давайте посмотрим как.

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

JavaScript позволяет деструктурировать массив напрямую следующим образом:

const [firstName, lastName, website] = [
  "Oluwatobi", 
  "Sofela", 
  "codesweetly.com"
];

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

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

Синтаксис деструктуризации массива при необходимости объявления переменных без инициализации

При использовании деструктуризации массива JavaScript позволяет отдельно объявлять переменные, а уже затем присваивать им значения.

Рассмотрим пример:

let firstName, lastName, website;

[firstName, lastName, website] = ["Oluwatobi", "Sofela", "codesweetly.com"];

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

А что если понадобится присвоить "Oluwatobi" переменной firstName, а остальные элементы массива — другой переменной? Как это сделать? Давайте разберемся и с этим вопросом.

Использование деструктуризации массива для присваивания переменной остальной части литерала массива

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

Рассмотрим пример:

const [firstName, ...otherInfo] = ["Oluwatobi", "Sofela", "codesweetly.com"];

console.log(firstName); // "Oluwatobi"
console.log(otherInfo); // ["Sofela", "codesweetly.com"]

Протестируйте код на StackBlitz

Примечание: оператор остатка всегда следует указывать в качестве последнего элемента деструктурирующего массива, иначе возникнет синтаксическая ошибка (SyntaxError).

А теперь представим, что нам нужно извлечь только значение "codesweetly.com". Обсудим способ, которым мы воспользуемся.

Использование деструктуризации массива для извлечения значений по любому индексу

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

const [, , website] = ["Oluwatobi", "Sofela", "codesweetly.com"];

console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

В коде выше мы использовали запятые для пропуска переменных в первой и второй позициях деструктурирующего массива.

Таким образом нам удалось связать переменную website с третьим значением из обычного массива, указанного справа от оператора присваивания (то есть "codesweetly.com").

Однако иногда значение, которое требуется извлечь из массива, является undefined. В этом случае JavaScript предоставляет возможность установить в деструктурирующем массиве значения по умолчанию. Рассмотрим этот случай подробнее.

Как работают значения по умолчанию при использовании деструктурирующего присваивания массива

Установить значения по умолчанию может быть полезно на тот случай, если значение, которое требуется извлечь из массива, не существует (или имеет значение undefined).

Ниже показано, как в деструктурирующем массиве задаются значения по умолчанию:

const [firstName = "Tobi", website = "CodeSweetly"] = ["Oluwatobi"];

console.log(firstName); // "Oluwatobi"
console.log(website); // "CodeSweetly"

Протестируйте код на StackBlitz

В коде выше мы задали "Tobi" и "CodeSweetly" в качестве значений по умолчанию для переменных firstName и website.

Поэтому при попытке извлечь значение с индексом 1 из массива, указанного в правой части, компьютер по умолчанию выводит "CodeSweetly", поскольку в массиве ["Oluwatobi"] существует значение только с нулевым индексом.

А что если нужно поменять значение переменной firstName на значение переменной website? И в этом случае мы можем воспользоваться деструктуризацией массива. Давайте посмотрим как.

Использование деструктуризации массива для обмена значений переменных

При помощи деструктурирующего присваивания массива можно поменять местами значения двух или нескольких переменных.

Рассмотрим пример:

let firstName = "Oluwatobi";
let website = "CodeSweetly";

[firstName, website] = [website, firstName];

console.log(firstName); // "CodeSweetly"
console.log(website); // "Oluwatobi"

Протестируйте код на StackBlitz

В коде выше мы использовали прямую деструктуризацию массива для повторного присваивания переменным firstName и website значений литерала массива, указанного справа от оператора присваивания.

Таким образом значение переменной firstName изменится с "Oluwatobi" на "CodeSweetly". В то же время значение переменной website изменится с "CodeSweetly" на "Oluwatobi".

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

Использование деструктуризации массива для извлечения значений из массива в параметры функции

Ниже приводится пример использования деструктуризации массива для извлечения значения из массива в параметр функции:

// Define an array with two items:
const profile = ["Oluwatobi", "Sofela"];

// Define a function with one destructuring array containing two parameters:
function getUserBio([firstName, lastName]) {
  return `My name is ${firstName} ${lastName}.`;
}

// Invoke getUserBio while passing the profile array as an argument:
getUserBio(profile);

// The invocation above will return:
"My name is Oluwatobi Sofela."

Протестируйте код на StackBlitz

В коде выше мы использовали параметр, который деструктурирует массив для извлечения значений из массива profile в параметры firstName и lastName функции getUserBio.

Примечание: параметр, деструктурирующий массив, обычно называют деструктурирующим параметром.

Рассмотрим еще один пример:

// Define an array with two string values and one nested array:
const profile = ["codesweetly.com", "Male", ["Oluwatobi", "Sofela"]];

// Define a function with two destructuring arrays containing a parameter each:
function getUserBio([website, , [userName]]) {
  return `${userName} runs ${website}`;
}

// Invoke getUserBio while passing the profile array as an argument:
getUserBio(profile);

// The invocation above will return:
"Oluwatobi runs codesweetly.com"

Протестируйте код на StackBlitz

В коде выше мы использовали два параметра, деструктурирующих массив, для извлечения значений из массива profile в параметры website и userName функции getUserBio.

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

Рассмотрим этот подход подробнее.

Вызов функции, содержащей параметры, деструктурирующие массив, без передачи ей аргументов

Рассмотрим приведенную ниже функцию:

function getUserBio([firstName]) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

Теперь вызовем функцию getUserBio, не передавая никакого аргумента в ее деструктурирующий параметр:

getUserBio();

Протестируйте код на CodeSandBox

После вызова вышеуказанной функции getUserBio браузер выдаст ошибку вроде TypeError: undefined is not iterable (Ошибка типа: undefined невозможно итерировать).

Сообщение TypeError возникает потому, что функции, содержащие деструктурирующий параметр, ожидают, что им будет передан хотя бы один аргумент.

Однако подобных сообщений об ошибках можно избежать, назначив деструктурирующему параметру аргумент по умолчанию.

Рассмотрим пример:

function getUserBio([firstName] = []) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

Обратите внимание, что в приведенном выше коде мы присвоили пустой массив в качестве аргумента по умолчанию для деструктурирующего параметра.

Теперь снова вызовем функцию getUserBio, не передавая никакого аргумента в ее деструктурирующий параметр:

getUserBio();

Результатом выполнения функции будет следующее:

"Do something else that does not need the destructuring parameter."
"My name is undefined."

Протестируйте код на CodeSandBox

Отметим, что необязательно использовать пустой массив в качестве аргумента по умолчанию для деструктурирующего параметра. Можно использовать любое другое значение, кроме null и undefined.

Теперь, когда мы знаем, что представляет собой деструктуризация массивов, предлагаю обсудить деструктуризацию объектов, чтобы увидеть различия.

Что представляет собой деструктуризация объектов в JavaScript?

Деструктуризация объекта (англ. object destructuring) — это особый синтаксис, позволяющий извлекать значения из объекта и записывать их в новые переменные с минимумом кода.

Например, без использования синтаксиса деструктуризации объекта значение из объекта копируется в новую переменную следующим образом:

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const firstName = profile.firstName;
const lastName = profile.lastName;
const website = profile.website;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

Обратите внимание, что в приведенном выше фрагменте много повторяющегося кода, что не удовлетворяет принципу DRY.

А теперь посмотрим, как деструктурирующее присваивание объекта позволит нам сделать код более аккуратным и лаконичным.

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const { firstName: firstName, lastName: lastName, website: website } = profile;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

Мы снова волшебным образом очистили наш код, поместив три новые переменные в объект свойств ({...}) и присвоив им значения из объекта profile.

Другими словами, мы сказали компьютеру, чтобы тот извлек значения из объекта profile и записал их в переменные, указанные слева от оператора присваивания.

В результате JavaScript парсит объект profile и копирует его первое значение ("Oluwatobi") в первую переменную деструктурирующего объекта (firstName).

Аналогичным образом компьютер извлекает второе значение ("Sofela") из объекта profile и записывает его во вторую переменную (lastName) деструктурирующего объекта.

Наконец JavaScript копирует третье значение из объекта profile ("codesweetly.com") в третью переменную (website) деструктурирующего объекта.

Отметим, что в { firstName: firstName, lastName: lastName, website: website } ключи являются ссылками на свойства объекта profile, при этом значения ключей представляют собой новые переменные.

Анатомия деструктурирующего присваивания объекта в JavaScript
Анатомия деструктурирующего присваивания объекта в JavaScript

Также можно использовать сокращенный синтаксис, чтобы сделать код более читабельным.

Рассмотрим пример:

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const { firstName, lastName, website } = profile;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

В коде выше мы сократили { firstName: firstName, age: age, gender: gender } до { firstName, age, gender }. Более подробно о сокращенной записи можно узнать здесь.

Обратите внимание, что в приведенном выше коде было показано, как присвоить значение из объекта переменной в случае, когда свойство объекта и переменная имеют одинаковые имена.

Однако можно присвоить значение свойства и переменной с другим именем. Давайте посмотрим как.

Использование деструктуризации объекта, когда имя свойства отличается от имени переменной

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

Рассмотрим пример:

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const { firstName: forename, lastName: surname, website: onlineSite } = profile;

console.log(forename); // "Oluwatobi"
console.log(surname); // "Sofela"
console.log(onlineSite); // "codesweetly.com"
console.log(website); // "ReferenceError: website is not defined"

Протестируйте код на CodeSandBox

В приведенном выше коде компьютер успешно извлек значения из объекта profile в переменные с именами forename, surname и onlineSite, несмотря на то что свойства и переменные имеют разные имена.

const profile = {
  lastName: { familyName: "Sofela" }
};

const { lastName: { familyName: surname } } = profile;

console.log(surname); // "Sofela"

Протестируйте код на StackBlitz

В приведенном выше коде компьютер успешно извлек значения из объекта profile в переменную с именем surname, несмотря на то что свойство и переменная имеют разные имена.

Примечание: const { lastName: { familyName: surname } } = profile — это эквивалент const surname = profile.lastName.familyName.

Обратите внимание, что мы деструктурировали объект profile путем ссылки на него. Однако деструктуризацию объекта можно делать и напрямую. Давайте посмотрим как.

Деструктуризация объекта напрямую

JavaScript допускает прямую деструктуризацию объекта свойств следующим образом:

const { firstName, lastName, website } = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

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

Синтаксис деструктуризации объекта при необходимости объявления переменных без инициализации

При использовании деструктуризации объекта JavaScript позволяет отделять объявление переменных от присваивания им значений.

Рассмотрим пример:

// Declare three variables:
let firstName, lastName, website;

// Extract values to the three variables above:
({ firstName, lastName, website } = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
});

// Invoke the three variables:
console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

Протестируйте код на StackBlitz

Примечание:

  • Деструктурирующее присваивание объекта нужно обязательно заключать в круглые скобки, чтобы компьютер понимал, что деструктуризация объекта — это литерал объекта, а не блок.

  • После круглых скобок деструктурирующего присваивания объекта необходимо ставить точку с запятой (;). Тогда компьютер не будет интерпретировать круглые скобки как вызов функции, которая могла находиться на предыдущей строке.

А что если понадобится присвоить значение "Oluwatobi" переменной firstName, а остальные значения из объекта — другой переменной? Как это сделать? Давайте разберемся и с этим вопросом.

Использование деструктуризации объекта для присваивания переменной остальной части объекта

JavaScript позволяет использовать оператор остатка внутри деструктурирующего объекта для присваивания переменной значений из остальной части литерала объекта.

Рассмотрим пример:

const { firstName, ...otherInfo } = {
  firstName: "Oluwatobi",
  lastName: "Sofela",
  website: "codesweetly.com"
};

console.log(firstName); // "Oluwatobi"
console.log(otherInfo); // {lastName: "Sofela", website: "codesweetly.com"}

Протестируйте код на StackBlitz

Примечание: оператор остатка всегда следует указывать в качестве последнего элемента деструктурирующего объекта, иначе возникнет синтаксическая ошибка (SyntaxError).

Однако иногда значение, которое требуется извлечь из объекта со свойствами, является undefined. В этом случае JavaScript предоставляет возможность установить в деструктурирующем объекте значения по умолчанию. Рассмотрим этот случай подробнее.

Как работают значения по умолчанию при использовании деструктурирующего присваивания объекта

Установить значения по умолчанию может быть полезно на тот случай, если значение, которое требуется извлечь из объекта, не существует (или имеет значение undefined).

Ниже показано, как в деструктурирующем объекте со свойствами задаются значения по умолчанию:

const { firstName = "Tobi", website = "CodeSweetly" } = {
  firstName: "Oluwatobi"
};

console.log(firstName); // "Oluwatobi"
console.log(website); // "CodeSweetly"

Протестируйте код на StackBlitz

В коде выше мы задали "Tobi" и "CodeSweetly" в качестве значений по умолчанию для переменных firstName и website.

Поэтому при попытке извлечь значение второго свойства объекта, указанного в правой части, компьютер по умолчанию выводит "CodeSweetly", поскольку в {firstName: "Oluwatobi"} присутствует только одно свойство.

А что если нужно поменять значение переменной firstName на значение переменной website? И в этом случае мы можем воспользоваться деструктуризацией объекта. Давайте посмотрим как.

Использование деструктуризации объекта для обмена значений переменных

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

Рассмотрим пример:

let firstName = "Oluwatobi";
let website = "CodeSweetly";

({ firstName, website } = {firstName: website, website: firstName});

console.log(firstName); // "CodeSweetly"
console.log(website); // "Oluwatobi"

Протестируйте код на StackBlitz

В коде выше мы использовали прямую деструктуризацию объекта для повторного присваивания переменным firstName и website значений литерала объекта, указанного справа от оператора присваивания.

Таким образом значение переменной firstName изменится с "Oluwatobi" на "CodeSweetly". В то же время значение переменной website изменится с "CodeSweetly" на "Oluwatobi".

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

Использование деструктуризации объекта для извлечения значений из свойств в параметры функции

Ниже приводится пример использования деструктуризации объекта для копирования значения свойства в параметр функции:

// Define an object with two properties:
const profile = {
  firstName: "Oluwatobi",
  lastName: "Sofela",
};

// Define a function with one destructuring object containing two parameters:
function getUserBio({ firstName, lastName }) {
  return `My name is ${firstName} ${lastName}.`;
}

// Invoke getUserBio while passing the profile object as an argument:
getUserBio(profile);

// The invocation above will return:
"My name is Oluwatobi Sofela."

Протестируйте код на StackBlitz

В коде выше мы использовали параметр, который деструктурирует объект для копирования значений из объекта profile в параметры firstName и lastName функции getUserBio.

Примечание: параметр, деструктурирующий объект, обычно называют деструктурирующим параметром.

Рассмотрим еще один пример:

// Define an object with three-parent properties:
const profile = {
  website: "codesweetly.com",
  gender: "Male",
  fullName: {
    firstName: "Oluwatobi",
    lastName: "Sofela"
  }
};

// Define a function with two destructuring objects containing a parameter each:
function getUserBio({ website, fullName: { firstName: userName } }) {
  return `${userName} runs ${website}`;
}

// Invoke getUserBio while passing the profile object as an argument:
getUserBio(profile);

// The invocation above will return:
"Oluwatobi runs codesweetly.com"

Протестируйте код на StackBlitz

В коде выше мы использовали два деструктурирующих параметра для копирования значений из объекта profile в параметры website и userName функции getUserBio.

Примечание: если вам не совсем понятен приведенный выше деструктурирующий параметр, возможно, вам будет полезно ознакомиться с этим разделом.

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

Рассмотрим этот подход подробнее.

Вызов функции, содержащей деструктурированные параметры, без передачи ей аргументов

Рассмотрим приведенную ниже функцию:

function getUserBio({ firstName }) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

Теперь вызовем функцию getUserBio, не передавая никакого аргумента в ее деструктурирующий параметр:

getUserBio();

Протестируйте код на CodeSandBox

После вызова вышеуказанной функции getUserBio браузер выдаст ошибку вроде TypeError: (destructured parameter) is undefined (Ошибка типа: (деструктурированный параметр) не определен).

Сообщение TypeError возникает потому, что функции, содержащие деструктурирующий параметр, ожидают, что им будет передан хотя бы один аргумент.

Однако подобных сообщений об ошибках можно избежать, назначив деструктурирующему параметру аргумент по умолчанию.

Рассмотрим пример:

function getUserBio({ firstName } = {}) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

Обратите внимание, что в приведенном выше коде мы присвоили пустой объект в качестве аргумента по умолчанию для деструктурирующего параметра.

Теперь снова вызовем функцию getUserBio, не передавая никакого аргумента в ее деструктурирующий параметр:

getUserBio();

Результатом выполнения функции будет следующее:

"Do something else that does not need the destructuring parameter."
"My name is undefined."

Протестируйте код на CodeSandBox

Отметим, что необязательно использовать пустой объект в качестве аргумента по умолчанию для деструктурирующего параметра. Можно использовать любое другое значение, кроме null и undefined.

Резюме

Деструктуризация массивов и объектов выполняется схожим образом. Основное различие между двумя деструктурирующими присваиваниями заключается, собственно, в том, что при деструктуризации массива значения извлекаются из массива, а при деструктуризации объекта — из объекта JavaScript.

Заключение

В этой статье мы рассмотрели, как работают деструктурирующие присваивания массивов и объектов в JavaScript и какие есть различия между двумя видами деструктурирующего присваивания.


Материал подготовлен в рамках курса «JavaScript Developer. Professional». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.

Теги:
Хабы:
Всего голосов 12: ↑4 и ↓8-4
Комментарии4

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS