解构赋值

语法

``````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

// Stage 4（已完成）提案中的特性
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}
``````

描述

``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
``````

JavaScript 中，解构赋值的作用类似于 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``````

默认值

``````var a, b;

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

交换变量

``````var a = 1;
var b = 3;

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

解析一个从函数返回的数组

``````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]``````

``````var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma``````

用正则表达式匹配提取值

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

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

console.log(parseProtocol('https://developer.mozilla.org/en-US/Web/JavaScript')); // "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}` 被认为是一个块而不是对象字面量。

给新的变量名赋值

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

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

默认值

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

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

给新的变量命名并提供默认值

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

console.log(aa); // 3
console.log(bb); // 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;
// now finally do some chart drawing
}

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

ES2015 版本

``````function drawES2015Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {})
{
// do some chart drawing
}

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

解构嵌套对象和数组

``````const metadata = {
translations: [
{
locale: 'de',
localization_tags: [],
last_edit: '2014-04-14T08:43:37',
title: 'JavaScript-Umgebung'
}
],
};

let {
title: englishTitle, // rename
translations: [
{
title: localeTitle, // rename
},
],

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: 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"``````

对象属性计算名和解构

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

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

对象解构中的 Rest

Rest/Spread Properties for ECMAScript 提案（阶段 4）将 rest 语法添加到解构中。Rest 属性收集那些尚未被解构模式拾取的剩余可枚举属性键。

``````let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10
b; // 20
rest; // { c: 30, d: 40 }``````

无效的 JavaScript 标识符作为属性名称

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

console.log(fizzBuzz); // "true"
``````

解构对象时会查找原型链（如果属性不在对象自身，将从原型链中查找）

``````// 声明对象 和 自身 self 属性
var obj = {self: '123'};
// 在原型链中定义一个属性 prot
obj.__proto__.prot = '456';
// test
const {self, prot} = obj;
// self "123"
// prot "456"（访问到了原型链）``````

规范

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
Destructuring assignment
Standard Initial definition.
ECMAScript (ECMA-262)
Destructuring assignment
Living Standard

浏览器兼容

BCD tables only load in the browser