Spec-Zone.ru › JavaScript

Деструктуризация

Baseline Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и в версиях браузеров. Она доступна в браузерах с января 2020 года.

Синтаксис деструктуризации — это синтаксис JavaScript, который позволяет распаковывать значения из массивов или свойства из объектов в отдельные переменные. Его можно использовать в местах, где принимаются данные (например, в левой части присваивания или в любом месте, где создаются новые привязки идентификаторов).

Попробуйте

let a, b, rest;
[a, b] = [10, 20];

console.log(a);
// Expected output: 10

console.log(b);
// Expected output: 20

[a, b, ...rest] = [10, 20, 30, 40, 50];

console.log(rest);
// Expected output: Array [30, 40, 50]

Синтаксис

const [a, b] = array;
const [a, , b] = array;
const [a = aDefault, b] = array;
const [a, b, ...rest] = array;
const [a, , b, ...rest] = array;
const [a, b, ...{ pop, push }] = array;
const [a, b, ...[c, d]] = array;

const { a, b } = obj;
const { a: a1, b: b1 } = obj;
const { a: a1 = aDefault, b = bDefault } = obj;
const { a, b, ...rest } = obj;
const { a: a1, b: b1, ...rest } = obj;
const { [key]: a } = obj;

let a, b, a1, b1, c, d, rest, pop, push;
[a, b] = array;
[a, , b] = array;
[a = aDefault, b] = array;
[a, b, ...rest] = array;
[a, , b, ...rest] = array;
[a, b, ...{ pop, push }] = array;
[a, b, ...[c, d]] = array;

({ a, b } = obj); // parentheses are required
({ a: a1, b: b1 } = obj);
({ a: a1 = aDefault, b = bDefault } = obj);
({ a, b, ...rest } = obj);
({ a: a1, b: b1, ...rest } = obj);

Описание

Выражения литералов объектов и массивов предоставляют простой способ создания пакетов данных ad hoc.

const arr = [a, b, c];

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

const arr = [1, 2, 3];
const [a, b, c] = arr;
// a = 1, b = 2, c = 3

Что касается объектов, сравните две пары строк ниже и увидите прямое соответствие внутри каждой пары.

const obj = { a, b, c };
const { a, b, c } = obj;
// Equivalent to:
// const a = obj.a, b = obj.b, c = obj.c;

const obj = { prop1: x, prop2: y, prop3: z };
const { prop1: x, prop2: y, prop3: z } = obj;
// Equivalent to:
// const x = obj.prop1, y = obj.prop2, z = obj.prop3;

Эта возможность аналогична функциям, присутствующим в таких языках, как Perl и Python.

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

Привязка и присваивание

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

В шаблонах привязки шаблон начинается с ключевого слова объявления (var, let или const). Затем каждое отдельное свойство должно быть либо привязано к переменной, либо далее деструктурировано.

const obj = { a: 1, b: { c: 2 } };
const {
  a,
  b: { c: d },
} = obj;
// Two variables are bound: `a` and `d`

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

const obj = { a: 1, b: { c: 2 } };
const { a } = obj; // a is constant
let {
  b: { c: d },
} = obj; // d is re-assignable

Во многих других синтаксисах, где язык привязывает переменную за вас, вы можете использовать шаблон привязки деструктуризации. К ним относятся:

  • Переменная цикла for...in, for...of и for await...of;
  • Параметры функции;
  • Переменная привязки catch.

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

const numbers = [];
const obj = { a: 1, b: 2 };
({ a: numbers[0], b: numbers[1] } = obj);
// The properties `a` and `b` are assigned to properties of `numbers`

Примечание: Скобки ( ... ) вокруг оператора присваивания необходимы при использовании деструктуризации литерала объекта без объявления.

{ a, b } = { a: 1, b: 2 } не является допустимым самостоятельным синтаксисом, поскольку { a, b } в левой части считается блоком, а не литералом объекта, согласно правилам операторов выражения. Однако ({ a, b } = { a: 1, b: 2 }) допустим, как и const { a, b } = { a: 1, b: 2 }.

Если ваш стиль кодирования не включает конечные точки с запятой, выражение ( ... ) должно предваряться точкой с запятой, или оно может использоваться для выполнения функции в предыдущей строке.

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

const numbers = [];
const obj = { a: 1, b: 2 };
const { a: numbers[0], b: numbers[1] } = obj;

// This is equivalent to:
//   const numbers[0] = obj.a;
//   const numbers[1] = obj.b;
// Which definitely is not valid.

Вы можете использовать шаблоны присваивания только в левой части оператора присваивания. Вы не можете использовать их с составными операторами присваивания, такими как += или *=.

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

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

const [a = 1] = []; // a is 1
const { b = 2 } = { b: undefined }; // b is 2
const { c = 2 } = { c: null }; // c is null

Значение по умолчанию может быть любым выражением. Оно будет вычислено только при необходимости.

const { b = console.log("hey") } = { b: 2 };
// Does not log anything, because `b` is defined and there's no need
// to evaluate the default value.

Оставшиеся свойства и оставшиеся элементы

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

Более формально, синтаксис ...rest называется "оставшиеся элементы" при деструктуризации массива и "оставшиеся свойства" при деструктуризации объекта, но мы часто совместно называем их "свойством остатка".

const { a, ...others } = { a: 1, b: 2, c: 3 };
console.log(others); // { b: 2, c: 3 }

const [first, ...others2] = [1, 2, 3];
console.log(others2); // [2, 3]

Свойство остатка должно быть последним в шаблоне и не должно иметь конечной запятой.

const [a, ...b,] = [1, 2, 3];

// SyntaxError: rest element may not have a trailing comma
// Always consider using rest operator as the last element

Как и в случае с любыми другими возможностями языка JavaScript, не происходит явного глубокого копирования. Свойство остатка создает новый объект (или массив), но все значения его элементов, если они являются ссылками на объекты, остаются прежними.

Примеры

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

Основное присваивание переменных

const foo = ["one", "two", "three"];

const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"

Деструктуризация с большим количеством элементов, чем в источнике

При деструктуризации массива из массива длиной N, указанного в правой части оператора присваивания, если количество переменных, указанных в левой части оператора присваивания, больше N, значения присваиваются только первым N переменным. Значения оставшихся переменных будут undefined.

const foo = ["one", "two"];

const [red, yellow, green, blue] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // undefined
console.log(blue); // undefined

Обмен значениями переменных

Значения двух переменных можно поменять местами в одном выражении деструктуризации.

Без деструктуризации для обмена значениями двух переменных требуется временная переменная (или, в некоторых низкоуровневых языках, трюк XOR-swap).

let a = 1;
let b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

const arr = [1, 2, 3];
[arr[2], arr[1]] = [arr[1], arr[2]];
console.log(arr); // [1, 3, 2]

Разбор массива, возвращенного функцией

Всегда было возможно возвращать массив из функции. Деструктуризация может сделать работу с возвращаемым значением массива более лаконичной.

В этом примере f() возвращает значения [1, 2] в качестве выходных данных, которые могут быть разобраны в одной строке с помощью деструктуризации.

function f() {
  return [1, 2];
}

const [a, b] = f();
console.log(a); // 1
console.log(b); // 2

Игнорирование некоторых возвращаемых значений

Вы можете игнорировать возвращаемые значения, которые вас не интересуют:

function f() {
  return [1, 2, 3];
}

const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

const [c] = f();
console.log(c); // 1

Вы также можете игнорировать все возвращаемые значения:

[, ,] = f();

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

Использование шаблона привязки в качестве свойства остатка

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

const [a, b, ...{ length }] = [1, 2, 3];
console.log(a, b, length); // 1 2 1
const [a, b, ...[c, d]] = [1, 2, 3, 4];
console.log(a, b, c, d); // 1 2 3 4

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

const [a, b, ...[c, d, ...[e, f]]] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c, d, e, f); // 1 2 3 4 5 6

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

const { a, ...{ b } } = { a: 1, b: 2 };
// SyntaxError: `...` must be followed by an identifier in declaration contexts

let a, b;
({ a, ...{ b } } = { a: 1, b: 2 });
// SyntaxError: `...` must be followed by an assignable reference in assignment contexts

Распаковка значений из совпадения регулярного выражения

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

function parseProtocol(url) {
  const parsedURL = /^(\w+):\/\/([^/]+)\/(.*)$/.exec(url);
  if (!parsedURL) {
    return false;
  }
  console.log(parsedURL);
  // ["https://developer.mozilla.org/en-US/docs/Web/JavaScript",
  // "https", "developer.mozilla.org", "en-US/docs/Web/JavaScript"]

  const [, protocol, fullHost, fullPath] = parsedURL;
  return protocol;
}

console.log(
  parseProtocol("https://developer.mozilla.org/en-US/docs/Web/JavaScript"),
);
// "https"

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

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

const [a, b] = new Map([
  [1, 2],
  [3, 4],
]);
console.log(a, b); // [1, 2] [3, 4]

Неитерируемые объекты не могут быть деструктурированы как массивы.

const obj = { 0: "a", 1: "b", length: 2 };
const [a, b] = obj;
// TypeError: obj is not iterable

Итераторы итерируются только до тех пор, пока не будут назначены все привязки.

const obj = {
  *[Symbol.iterator]() {
    for (const v of [0, 1, 2, 3]) {
      console.log(v);
      yield v;
    }
  },
};
const [a, b] = obj; // Only logs 0 and 1

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

const obj = {
  *[Symbol.iterator]() {
    for (const v of [0, 1, 2, 3]) {
      console.log(v);
      yield v;
    }
  },
};
const [a, b, ...rest] = obj; // Logs 0 1 2 3
console.log(rest); // [2, 3] (an array)

Деструктуризация объектов

Основное присваивание

const user = {
  id: 42,
  isVerified: true,
};

const { id, isVerified } = user;

console.log(id); // 42
console.log(isVerified); // true

Присваивание новым именам переменных

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

const o = { p: 42, q: true };
const { p: foo, q: bar } = o;

console.log(foo); // 42
console.log(bar); // true

Здесь, например, const { p: foo } = o извлекает из объекта o свойство с именем p и присваивает его локальной переменной с именем foo.

Присваивание новым именам переменных и предоставление значений по умолчанию

Свойство может быть одновременно:

  • Извлечено из объекта и присвоено переменной с другим именем.
  • Получить значение по умолчанию, если извлеченное значение равно undefined.
const { a: aa = 10, b: bb = 5 } = { a: 3 };

console.log(aa); // 3
console.log(bb); // 5

Распаковка свойств из объектов, переданных в качестве параметра функции

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

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

const user = {
  id: 42,
  displayName: "jdoe",
  fullName: {
    firstName: "Jane",
    lastName: "Doe",
  },
};

Здесь мы показываем, как распаковать свойство переданного объекта в переменную с тем же именем. Параметр { id } указывает, что свойство id объекта, переданного в функцию, должно быть распаковано в переменную с тем же именем, которая затем может быть использована внутри функции.

function userId({ id }) {
  return id;
}

console.log(userId(user)); // 42

Вы можете определить имя распакованной переменной. Здесь мы распаковываем свойство с именем displayName и переименовываем его в dname для использования внутри тела функции.

function userDisplayName({ displayName: dname }) {
  return dname;
}

console.log(userDisplayName(user)); // "jdoe"

Вложенные объекты также могут быть распакованы. Пример ниже показывает, что свойство fullname.firstName распаковывается в переменную с именем name.

function whois({ displayName, fullName: { firstName: name } }) {
  return `${displayName} is ${name}`;
}

console.log(whois(user)); // "jdoe is Jane"

Установка значения по умолчанию для параметра функции

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

Ниже мы показываем функцию, в которой значение размера по умолчанию равно 'big', координаты по умолчанию — x: 0, y: 0, а радиус по умолчанию — 25.

function drawChart({
  size = "big",
  coords = { x: 0, y: 0 },
  radius = 25,
} = {}) {
  console.log(size, coords, radius);
  // do some chart drawing
}

drawChart({
  coords: { x: 18, y: 30 },
  radius: 30,
});

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

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

Дополнительную информацию см. в разделе Параметры по умолчанию > Деструктурированный параметр с присваиванием значения по умолчанию.

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

const metadata = {
  title: "Scratchpad",
  translations: [
    {
      locale: "de",
      localizationTags: [],
      lastEdit: "2014-04-14T08:43:37",
      url: "/de/docs/Tools/Scratchpad",
      title: "JavaScript-Umgebung",
    },
  ],
  url: "/en-US/docs/Tools/Scratchpad",
};

const {
  title: englishTitle, // rename
  translations: [
    {
      title: localeTitle, // rename
    },
  ],
} = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"

Итерация for...of и деструктуризация

const people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith",
    },
    age: 35,
  },
  {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones",
    },
    age: 25,
  },
];

for (const {
  name: n,
  family: { father: f },
} of people) {
  console.log(`Name: ${n}, Father: ${f}`);
}

// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"

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

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

const key = "z";
const { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"

Недопустимый идентификатор JavaScript в качестве имени свойства

Деструктуризация может использоваться со свойствами, имена которых не являются допустимыми идентификаторами JavaScript, путем предоставления альтернативного допустимого идентификатора.

const foo = { "fizz-buzz": true };
const { "fizz-buzz": fizzBuzz } = foo;

console.log(fizzBuzz); // true

Деструктуризация примитивных значений

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

const { a, toFixed } = 1;
console.log(a, toFixed); // undefined ƒ toFixed() { [native code] }

Как и при доступе к свойствам, деструктуризация null или undefined вызывает TypeError.

const { a } = undefined; // TypeError: Cannot destructure property 'a' of 'undefined' as it is undefined.
const { b } = null; // TypeError: Cannot destructure property 'b' of 'null' as it is null.

Это происходит даже при пустом шаблоне.

const {} = null; // TypeError: Cannot destructure 'null' as it is null.

Комбинированная деструктуризация массивов и объектов

Деструктуризацию массивов и объектов можно комбинировать. Предположим, вам нужен третий элемент в массиве props ниже, а затем вам нужно свойство name в объекте, вы можете сделать следующее:

const props = [
  { id: 1, name: "Fizz" },
  { id: 2, name: "Buzz" },
  { id: 3, name: "FizzBuzz" },
];

const [, , { name }] = props;

console.log(name); // "FizzBuzz"

Цепочка прототипов просматривается при деконструкции объекта

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

const obj = {
  self: "123",
  __proto__: {
    prot: "456",
  },
};
const { self, prot } = obj;

console.log(self); // "123"
console.log(prot); // "456"

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-destructuring-assignment
ECMAScript® 2027 Language Specification
# sec-destructuring-binding-patterns

Совместимость с браузерами

Desktop Mobile Server
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
destructuring
49
14
41Firefox provided a non-standard destructuring implementation from Firefox 2 to 40.
36
8
49
41Firefox for Android provided a non-standard destructuring implementation from Firefox for Android 4 to 40.
36
8
5.0
49
8
1.0.0
1.0
6.0.0
computed_property_names
49
14
41
36
10
49
41
36
10
5.0
49
10
1.0.0
1.0
6.0.0
rest_in_arrays
49
16
41
36
9.1
49
41
36
9.3
5.0
49
9.3
1.0.0
1.0
6.0.0
rest_in_objects
60
79
55
47
11.1
60
55
44
11.3
8.0
60
11.3
1.0.0
1.0
8.3.0

См. также

  • Операторы присваивания
  • ES6 in Depth: Destructuring на hacks.mozilla.org (2015)

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API