Деструктуризація
Деструктуризація (деструктуризаційне присвоєння) - 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 (ECMA-262) The definition of 'Destructuring assignment' in that specification. |
Living Standard |
Сумісність з браузерами
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 щоб довідатись більше.