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

Деструктуризація (деструктуризаційне присвоєння) - JavaScript вираз, який дозволяє витягувати дані з масивів та об’єктів в окремі змінні.

Ситнаксис

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({a, b} = {a: 10, b: 20});
console.log(a); // 10
console.log(b); // 20

// Експерементальний синтаксис (ще не стандартизований)
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}); 

Опис

Вирази присвоєння літералів об’єктів та масивів надають простий спосіб створювати ad hoc (ад-гок) структури даних.

var x = [1, 2, 3, 4, 5];

Деструктуризаційне присвоєння використовує подібний синтаксис, де ліва сторона виразу визначає елементи, що потрібно витягнути зі змінної-джерела (правої сторони).

var x = [1, 2, 3, 4, 5];
var [y, z] = x;
console.log(y); // 1
console.log(z); // 2

Це подібне до способів, що доступні у мовах програмування на кшталт Perl та Python.

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

Звичайне присвоєння

var foo = ['one', 'two', 'three'];

var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"

Присвоєння, окреме від оголошення

Значення може бути присвоєне змінній окремо від оголошення цієї змінної.

var a, b;

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

Значення за промовчанням

Змінній може бути присвоєне значення за промовчанням у випадку, коли витягнуте значення є undefined.

var a, b;

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

Обмін змінних

Дві змінні можуть обмінятися значеннями за допомогою одного деструктуризаційного виразу. 

Без деструктуризації, обмін двох значеннь потребує тимчасової змінної (або в деяких низькорівневих мовах XOR-обміну).

var a = 1;
var b = 3;

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

Розбір масиву, поверненого з функції

Завжди було можливо повернути масив із функції. Деструктуризація може зробити обробку повернутого масиву більш виразною.

У цьому прикладі f() повертає значення [1, 2], які можуть бути розібрані одним рядком коду за допомогою деструктуризації.

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

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

Пропуск деяких значень

Можна пропустити повернуті значення, які тобі не цікаві:

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

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

Також можна пропустити всі значення (але навіщо?):

[,,] = f();

Присвоєння решти масиву змінній

Деструктуризуючи масив, можна присвоїти змінній решту його елементів за допомогою оператора розпакування:

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

Зауваж, що буде видана помилка SyntaxError, якщо поставити прикінцеву кому в лівій частині виразу за елементом решти:

var [a, ...b,] = [1, 2, 3];
// SyntaxError: елемент решти не може мати прикінцевої коми

Витягнення значеннь з масиву збігів регулярного виразу

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

var url = 'https://developer.mozilla.org/en-US/Web/JavaScript';

var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]

var [, protocol, fullhost, fullpath] = parsedURL;

console.log(protocol); // "https"

Деструктуризація об’єктів

Звичайне присвоєння

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true 

Присвоєння, окреме від оголошення

Значення може бути присвоєне змінній окремо від оголошення цієї змінної.

var a, b;

({a, b} = {a: 1, b: 2});

Дужки ( .. ) навколо виразу присвоєння необхідні при деструктуризаційному присвоєні об’єкта без оголошення.

Вираз {a, b} = {a: 1, b: 2} сам по собі є синтаксично неправильним, оскільки {a, b} в лівій його частині розглядається як блок коду, а не як об’єкт.

Проте, ({a, b} = {a: 1, b: 2}) є правильним, як і var {a, b} = {a: 1, b: 2}

Присвоєння новим змінним

Значення може бути отримане з об’єкту та присвоєне змінній з іменем, інакшим від назви властивості об’єкта.

var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
 
console.log(foo); // 42 
console.log(bar); // true  

Значення за промовчанням

Змінній може бути присвоєне значення за промовчанням у випадку, коли витягнуте значення з об’єкту є undefined.

var {a = 10, b = 5} = {a: 3};

console.log(a); // 3
console.log(b); // 5

Встановлення значення за промовчанням аргументам функції

ES5 версія

function drawES5Chart(options) {
  options = options === undefined ? {} : options;
  var size = options.size === undefined ? 'big' : options.size;
  var cords = options.cords === undefined ? {x: 0, y: 0} : options.cords;
  var radius = options.radius === undefined ? 25 : options.radius;
  console.log(size, cords, radius);
  // тепер, врешті, малюй діаграму
}

drawES5Chart({
  cords: {x: 18, y: 30},
  radius: 30
});

ES2015 версія

function drawES2015Chart({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}) {
  console.log(size, cords, radius);
  // малюй діаграму
}

drawES2015Chart({
  cords: {x: 18, y: 30},
  radius: 30
});

Вкладена деструктуризація об’єктів та масивів

var metadata = {
    title: 'Scratchpad',
    translations: [
       {
        locale: 'de',
        localization_tags: [],
        last_edit: '2014-04-14T08:43:37',
        url: '/de/docs/Tools/Scratchpad',
        title: 'JavaScript-Umgebung'
       }
    ],
    url: '/en-US/docs/Tools/Scratchpad'
};

var {title: englishTitle, translations: [{title: localeTitle}]} = metadata;

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

For of цикл та деструктуризація

var 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 (var {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"

Витягнення полів з об’єктів, що передані аргументами в функцію

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

function whois({displayName, fullName: {firstName: name}}) {
  console.log(displayName + ' is ' + name);
}

var user = { 
  id: 42, 
  displayName: 'jdoe',
  fullName: { 
      firstName: 'John',
      lastName: 'Doe'
  }
};

console.log('userId: ' + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"

Це витягує id, displayName та firstName з об’єкта user та виводить їх.

Розраховувані імена властивостей об’єкта та деструктуризація

Розраховувані імена властивостей об’єкта можуть також бути використані разом із деструктуризацією

let key = 'z';
let {[key]: foo} = {z: 'bar'};

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

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

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Destructuring assignment' in that specification.
Standard Initial definition.
ECMAScript 2017 Draft (ECMA-262)
The definition of 'Destructuring assignment' in that specification.
Draft  

Сумісність з браузерами 

Feature Chrome Firefox (Gecko) Edge Internet Explorer Opera Safari
Basic support 49.0 2.0 (1.8.1) 14 No support No support 7.1
Computed property names 49.0 34 (34) 14 No support No support No support
Spread operator 49.0 34 (34) 12[1] ? ? ?
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support No support 49.0 1.0 (1.0) No support No support 8 49.0
Computed property names No support 49.0 34.0 (34) No support No support No support 49.0
Spread operator No support 49.0 34.0 (34) ? ? ? 49.0

[1] Потребує ввімкнення "Enable experimental Javascript features" в налаштуваннях `about:flags`

Примітки для Firefox

  • Firefox надавав нестандартне розширення мови в JS1.7 для деструктуризації. Це розширення було видалене в Gecko 40 (Firefox 40 / Thunderbird 40 / SeaMonkey 2.37). Дивись bug 1083498.
  • Починаючи від Gecko 41 (Firefox 41 / Thunderbird 41 / SeaMonkey 2.38) та згідно зі спецефікацією ES2015, деструктуризаціїні вирази в дужках, на кшталт ([a, b]) = [1, 2] or ({a, b}) = { a: 1, b: 2 }, зараз вважаються неправильними та будуть видавати помилку SyntaxError. Дивись Jeff Walden's blog post та bug 1146136 щоб довідатись більше.

Дивись також

Мітки документа й учасники

 Зробили внесок у цю сторінку: trofima
 Востаннє оновлена: trofima,