0%

ES6 語法糖 - 解構賦值與其餘參數

解構賦值

解構賦值 (Destructuring assignment) 語法是一種 JavaScript 運算式,可以把陣列或物件中的資料解開擷取成為獨立變數。

通常我們拿到的資料會是物件與陣列所組成,為了處理這些資料,需要使用迴圈、判斷等語法來取得相對應的資料,而陣列所包含的資料可能是複合性的或者物件屬性名稱不是我們要的,這時可以利用解構、展開運算子以及其餘參數混合使用達成我們的處理目的。若要透過函式處理更多事情,也能在函式的參數中使用。

在以下的段落會介紹 :

  • 陣列解構
  • 物件解構
  • 解構預設值
  • 其餘參數與展開運算子

陣列解構

變數賦值

  • 宣告多個變數後,將它們用陣列的中括號包起來 let [變數1, 變數2]
  • 變數會對應陣列中絕對位置的陣列值,順序為由左至右
  • 若缺少對應值,該變數則為 undefined

均有對應變數

1
2
3
4
5
// 所有變數在對應的位置賦值
const array = [2, 4, 6, 8, 10]
let [a, b, c, d, e] = array
console.log(a, b, c ,d, e)
// 2 4 6 8 10

缺少變數

1
2
3
4
5
// 有限的變數在對應的位置賦值
const array = [2, 4, 6, 8, 10]
let [x, , , y, z] = array
console.log(x, y, z)
// 2 8 10

缺少對應值

1
2
3
4
5
6
// 變數皆已宣告,但對應位置沒有賦予值
// 如同直接執行 console.log(d)
const array = [2, 4, , , 10]
let [a, b, c, d, e] = array
console.log(a, b, c ,d, e)
// 2 4 undefined undefined 10

其餘參數賦予新陣列

1
2
3
4
5
// 可以利用其餘參數將剩下的元素形成一組新陣列
const array = [2, 4, 6, 8, 10]
let [a, b, ...c] = array
console.log(a, b, c)
// 2 4 [6, 8, 10]

變數交換

  • 利用解構將變數賦值後,再將它們的值做交換
  • 利用解構方式將變數值做交換時,上一行必須要有分號,否則會出錯
  • 若使用套件 ESLint檢查的話,需要換個方式寫,將外層以大括號區隔
    1
    2
    3
    4
    5
    6
    7
    8
    let [seatA, seatB] = ['Jay', 'Vic']
    console.log(seatA, seatB); // "Jay" "Vic"

    [seatA, seatB] = [seatB, seatA]
    // 不用分號的寫法
    // {[seatA, seatB] = [seatB, seatA]}
    console.log(seatA, seatB)
    // "Vic" "Jay"

字串解構

  • 可以將字串每一個字元作為變數值
    1
    2
    3
    4
    let str = 'Vic'
    let [a, b ,c] = str
    console.log(a, b, c)
    // "V" "i" "c"

物件解構

  • 宣告多個變數後,將它們用物件的大括號包起來 let {變數1, 變數2}
  • 但它沒有順序

一般物件解構

1
2
3
4
5
6
7
8
let person = {
name: 'Vic',
age: 18
}
// 宣告 name與 age為變數,只不過與物件內的屬性名稱相同
let {name, age} = person
console.log(name, age)
// "Vic" 18

無宣告物件解構

  • 未宣告的物件屬性值可以解構給已宣告變數
    • 如同上一個範例,變數的值為物件的屬性值
    • 這裡不需將物件宣告
  • 但變數名稱需與未宣告的物件屬性名稱相同
  • 已宣告的變數名稱可以再次給予新名稱
1
2
3
let {name:anonymous, age:anonymousAge} = {name:'ccc', age:18} 
console.log(anonymous, anonymousAge)
// "ccc" 18

解構預設值

  • 在解構陣列與物件時,若沒有對應的變數值,預設會是 undefined
  • 可以在宣告時先給予一個預設值

陣列解構預設值

1
2
3
let [name='匿名登入', age='隱藏年齡'] = ['Vic']
console.log(name, age)
// "Vic" "隱藏年齡"

物件解構預設值

  • 給予預設值的同時,也可以賦予新的變數名稱,但只有物件可以
  • let { 已宣告變數名:新的變數名 = 預設值 }
  • let {name:anonymous = '匿名登入'}
1
2
3
let {name:anonymous='匿名登入', age='隱藏年齡'} = {}
console.log(anonymous, age)
// "匿名登入" "隱藏年齡"

函式與預設值

  • 可以將物件解構作為函式的參數並設定預設值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 單純參數預設值 */
const fnA = (name='匿名登入') => {
console.log(name)
}
fnA() // "匿名登入"

/* 物件解構預設值 */
const fnB = ({name='匿名登入', height=150}={}) => {
console.log(name, height)
}
const person = {
name:'Vic',
height:180
}
fnB() // "匿名登入" 150
fnB(person) // "Vic" 180

其餘參數與展開運算子

  • 寫法為三個點 ...
  • 必須寫在變數名稱前面 ...變數名稱
  • 兩者常會混淆,它們寫法相同,但行為不同

其餘參數

其餘參數(rest parameter) 語法可以讓我們表示不確定數量的參數,並將其視為一個陣列。

  • 可以將剩餘資料收集並組成一個新陣列
  • 它為實體陣列,也就是說,它可以使用 forEach()length等等…
  • 它必需在最後一個位置才能使用

收集剩餘資料

再看一次陣列解構中,有提到其餘參數的運用 :

1
2
3
4
5
6
// 陣列解構後賦予變數值
// 利用其餘參數將變數 c賦予一組新陣列
const array = [2, 4, 6, 8, 10]
let [a, b, ...c] = array
console.log(a, b, c)
// 2 4 [6, 8, 10]

展開運算子

展開運算子(…) 允許可迭代的陣列或字串展開成0到多個參數(如果是function的話)或是0到多個元素(如果是array或字組的話),或如果是物件的話則展開成0到多個key-value pair。

  • 若對陣列展開,它會 return陣列中每一個值
  • 若對物件展開,它會 return物件中每一個屬性名稱
  • 若對字串展開,它為類陣列,會 return類陣列中每一個值

將陣列展開

1
2
3
const array = [2, 4, 6, 8, 10]
console.log(...array)
// 2 4 6 8 10

將字串展開

1
2
3
let name ='Vic'
console.log(...name)
// "V" "i" "c"

綜合使用

1
2
3
4
5
6
7
8
9
const array = [2, 4, 6, 8, 10]
const fn = (a, b, ...c) => { // 將剩餘陣列值收集
console.log(a+b)
// reduce() 可以將陣列內所有值累加
console.log(c.reduce((d,e) => d+e))
}
fn(...array) // 將陣列展開
// 6
// 24

解構賦值與其餘參數

參考別人的 JS寫法時,常會看到利用解構賦值與其餘參數的混和運用,但自己寫的時候卻常混淆它們的行為,三種不同的行為模式卻可以達成類似的目的,於是寫了這篇給自己看。要是能善加利用解構賦值、展開運算子以及其餘參數,對於函式的參數設計上會有很大的幫助。

參考來源

  1. MDN - 解構賦值
  2. MDN - 其餘參數
  3. MDN - 展開運算子
  4. 卡斯伯 - 鐵人賽:ES6 解構賦值
  5. 從ES6開始的JavaScript學習生活 - 解構賦值
  6. 從ES6開始的JavaScript學習生活 - 展開運算符與其餘運算符
  7. realdennis - 解構賦值 — 設計函數時的小技巧 JavaScript