Destructuring assignment 解構賦值

2020-05-22
JS新手村

解構賦值 (Destructuring assignment)
可以把陣列或物件中的資料解開擷取成為獨立變數。

用於提取(extract)陣列或物件中的資料,新語法可以讓程式碼在撰寫時更為簡短與提高閱讀性。
Day 08: ES6篇 - Destructuring Assignment(解構賦值)

解構賦值可以想像是鏡子的概念,將右方的資料往左邊送,然後會一個位置對一個值 (但沒有像鏡子左右顛倒)。
卡斯伯-鐵人賽:ES6 解構賦值

語法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//字串-拆成一個一個字元
const ddhung = 'iscute';
[a,b,c,d,e] = ddhung;
console.log(a) // i

//陣列
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]

//如果左方多於右方會出現undefined
const family = ['Robert', 'Grace', 'DD'];
const [dad, mon, baby, dog] = family;
console.log(baby, dog) // DD undefined

//物件
({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});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}

解構順序依左至右

1
2
3
4
const a = [1, 2, 3, 4]
const [x, y] = a
console.log(x) //1
console.log(y) //2

陣列解構

陣列以順序的索引值對應

1
2
3
4
5
const foo = ['one', 'two', 'three'];
const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"

預設值
當解構還原陣列對應的元素是undefined,變數為預設值

1
2
3
4
let a , b;
[a = 5, b = 10] = [1];
console.log(a) //1
console.log(b) //10

變數交換👍
兩個變數可以透過一個解構指派式交換

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

解析自函式回傳的陣列
函式可以回傳陣列,而解構指派示可以讓回傳值更簡潔

1
2
3
4
5
6
7
8
function f(){
return [1, 2]
}

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

忽略回傳值

1
2
3
4
5
6
7
function f() {
return [1, 2, 3];
}

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

物件解構

物件以物件的屬性名稱(key)做對應,沒有順序性
基本指派示

1
2
3
4
const o = {p: 42, q: true};
const {p, q} = o;
console.log(p) //42
console.log(q) //true

就目前解讀為什麼要這樣做(一)?
如果沒有const {p, q} = o;

1
2
console.log(p) //p is not defined`
console.log(o.p) //42

透過解構賦值後,可以直接透過物件的key取到value

為什麼要這樣做(二)?

1
2
3
4
5
6
const o = {p: 42, q: true};
//一般寫法
let p = o.p
let q = o.q
//解構賦值寫法
const {p, q} = o; //結束!

無宣告指派

1
2
3
let a, b;
({a, b} = {a: 1 , b: 2}); //此段同const {a, b } = {a: 1 , b: 2},結尾分號為必須
console.log(a) //1

⚠️ 針對物件解構時,指派示必須加上()
{a, b} = {a: 1 , b: 2} 左邊的{a,b}會被視為程式碼區塊而非物件

預設值
當解構物件中對應的值為undefined時,變數可以設定預設值

1
2
3
const {a = 10, b = 5} = {a: 3};
console.log(a) //3
console.log(b) //5
1
2
3
4
const {a: aa = 10, b: bb = 5} = {a: 3};

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

當函數的parameter為物件時

1
2
3
4
5
6
7
8
9
10
11
12
const userDD = {id: 42, displayName: 'DD', fullName:{firstName: 'Hung',lastName: 'Di'}}

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

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

console.log(userId(userDD)) //42
console.log(whois(userDD)) //DD is Hung

從物件中提出的id, displayNamefirstName 並印出

設定函式parameter為物件,且有預設值

1
2
3
4
5
6
7
8
function drawChart({size = 'big',coords = {x: 0, y: 0},radius = 25}={}){
console.log(size, coords, radius);
}

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

⚠️ drawChart的parameter中,左方的解構式被指派到一個空物件,
{size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}
如果沒有寫右方的指派式,函式在呼叫時會找出最少一個參數。指派到空物件的作法,可以直接不使用參數呼叫drawChart();

範例

循環取出的解構

1
2
3
4
5
6
7
8
const people = [{name: 'Mike Smith',family:{mother: 'Sally', father: 'Joey Smith'},age: 35},
{name: 'DD Hung', family:{mother: 'Grace', father: 'Robert Hung'}, age: 22}]

for(const {name: n , family: {father: f}} of people){
console.log('Name: '+n+' Father: '+f)
}
//Name: Mike Smith Father: Joey Smith
//Name: DD Hung Father: Robert Hung

題目
宣告兩個具有5個元素的整數陣列 arr1arr2 ,並利用陣列設定初值的方式,將 arr1[0] ~ arr1[4] 分別設值為 2, 3, 1, 7, 9, arr2[0] ~ arr2[4] 分別設值為 8, 7, 9, 3, 1,將 arr1 與 arr2 兩陣列對應項相加,列印出相加後的陣列

1
2
3
4
5
6
//js09.js 介面
const { main } = require("./js09_module");
const arr1 = [2, 3, 1, 7, 9];
const arr2 = [8, 7, 9, 3, 1];
const result = main(arr1,arr2);
console.log(result); //[10, 10, 10, 10, 10]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//js09_module 程式
function sumValue(inputArray) {
const length = inputArray.arr1.length;
let newArray = [];
for (let i = 0; i < length; i++) {
newArray[i] = inputArray.arr1[i] + inputArray.arr2[i];
}
return newArray;
}

function main(array1, array2) {
return sumValue({array1, array2});//解構賦值
}
module.exports = { main };

解釋

js09_module中第12行

1
sumValue({arr1,arr2}) //為sumValue({array1:array1, array2:array2:})的簡寫

function sumValue(inputArray)帶入參數{array1, array2}

在第3行中

1
const length = inputArray.arr1.length;

相當於以下語法:

1
const length = {array1: array1= [2, 3, 1, 7, 9], array2: array2= [8, 7, 9, 3, 1]}.array1.length;

下面的語法就以此類推啦~

換一個比較短的例子會比較好理解

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

參考

Day 08: ES6篇 - Destructuring Assignment(解構賦值)
MDN - Destructuring assignment