# 解構賦值

## 語法

js
``````let 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(finished) proposal
({ 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}
``````

## 描述

js
``````const x = [1, 2, 3, 4, 5];
``````

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

Perl 和 Python 也有類似的語法和功能。

## 陣列解構

### 基本變數指定敘述

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

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

### 宣告指派分開敍述

js
``````let a, b;

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

### 預設值

js
``````let a, b;

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

### 變數交換

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

### 解析自函式回傳的陣列

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

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

### 忽略某些回傳值

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

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

js
``````[, ,] = f();
``````

### 把矩陣剩餘部分解構到一個變數

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

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

// SyntaxError 語法錯誤: 其餘元素不可以跟隨結尾逗號
// 需要把其餘運算子放在最後的元素
``````

### 從正則運算式的比對結果取值

js
``````function parseProtocol(url) {
const 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"]

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

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

## 物件解構

### 基本指派式

js
``````const o = { p: 42, q: true };
const { p, q } = o;

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

### 無宣告指派

js
``````let a, b;

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

`{a, b} = {a: 1, b: 2}` 不是有效的獨立語法，因為左邊的 `{a, b}` 被視為程式碼區塊而非物件。

`( ... )` 表達式前句需要以分號結束，否則可能把上一句視為函式隨即執行。

### 指派到新的變數名稱

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

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

### 預設值

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

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

### 指定新的變數名稱及預設值

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

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

### 從作為函式參數的物件中提出某屬性的值

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

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

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

console.log(userId(user)); // 42
console.log(whois(user)); // "jdoe is John"
``````

### 設定函式參數的預設值

js
``````function drawChart({
size = "big",
coords = { x: 0, y: 0 },
} = {}) {
// do some chart drawing
}

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

### 巢狀物件或陣列的解構

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

### 循環取出的解構

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

### 以物件演算屬性名稱解構

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

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

### 在物件解構時使用其餘變數

ECMAScript 中的其餘/展開屬性在 proposal (stage 4) 新增了在解構式內使用其餘 (rest) 語法的定義。其餘屬性可以收集解構式中沒有指定的屬性值。

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

### 不符合 JavaScript 識別字的屬性名稱

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

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

### 混合使用矩陣及物件解構

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

const [, , { name }] = props;

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

### 物件解構時的原型鏈追溯

```let obj = {self: '123'};
obj.__proto__.prot = '456';
const {self, prot} = obj;
// self "123"