筆記從 ES2015 / ES2016 / ES2017 / ES2018 / ES2019 / ES2020 以來,JS 所加入的新語言特性。使用的情境新語言特性不僅是為了減少對第三方套件的依賴 (Lodash),也是基於 ESLint 上 Clean Code、Best Practices 規範要求。熟悉新語言特性不僅能夠使 JS 開發更加快速也能夠提升閱讀性。
說明
本篇筆記為 Modern JS 所相關的 Spread、Rest、Destructuring 語法,同樣都是使用了 … 的符號,但卻有不同的情境語意。
Rest Parameters
在參數中使用 Three Dots 修飾參數,可以將複數個引數(Arguments)轉換為 Array,稱為 Rest Parameters。Rest Parameters 必須在複數參數最後順序使用,且僅允許一個 Rest Parameters。
Rest Parameters 的使用位置在 fucntion 的參數宣告區塊,使用的情境如 function 可以將引入包裝成一個 Array,以方便使用 Array 相關的 Method 進行處理。
const countIf = function (minimum, ...args){
return args.filter(e => e > minimum).length;
}
countIf(3, 2, 3, 4, 5, 6)
// 3
Spread Operator
不同於 Rest 是將數個引數集合成 Array,Spread 則是將陣列中的各元素拆解為引數。Spread Operator 使用的位置在 Array 當中,用於展開其他 Array 的 elements。
例如在 Literal Array 可以將其他的 Array Element 加入其中:
const even = [2, 4, 6]
const combined = [1, 3, 5, ...even]
// [1, 3, 5, 2, 4, 6]
或者可以為作為合併 Array 的使用目的:
const even = [2, 4, 6]
const odd = [1, 3, 5]
const numbers = [...even, ...odd]
// 2, 4, 6, 1, 3, 5
也可以用於複製 Array,但是 Shadow Copy 而非 Deep Copy,如果 Array 中的 element 為 Object 只會複製參照,而不會重新產生新的 Object。
let games = [
{name: 'DQB2', qty: 1},
{name: 'DQ5', qty: 2}
]
let copyGames = [...games]
copyGames[0].qty = 2;
// games' object is affteced
console.log(games[0].qty)
// 2
Destructuring Array
Destructuring 可以用於為變數賦值。
[a, b, c] = [1, 2, 3]
//a = 1, b = 2, c = 3
[e, f] = [4, 5, 6]
//e = 4, f = 5
[g, h] = [7]
//g = 7, h = undefined
Rest
也可以用 Rest 的方式,將部分的值另外集合起來作為新的 Array。
[x, y, ...arr] = [1, 2, 3, 4, 5]
// x = 1, y = 2, arr = [3, 4, 5]
default value
[x = 10, y = 15] = [20]
//x = 20, y = 15
Nested Array Mapping
巢狀的 Array 在解構賦值上也有對應的方式。
[
name,
job,
[item1, item2, item3]
] =
[
'Loto',
'Warrior',
['Flame Sword', 'Full Plate', 'Herb']
]
// name = 'Loto'
// job = 'Warrior'
// item1 = 'Flame Sword'
// item2 = 'Full Plate'
// item3 = 'Herb'
交換數值的應用
在 python 可以輕鬆交換變數數值的功能,藉由 Destructuring 也可以輕鬆處理囉 😋
let x = 2, y = 7;
[x, y] = [y, x]
// x = 7, y = 2
擴充函式回傳的彈性
讓函式可以回傳多個數值,並且用 Array 包裝,接收端則使用 Destructuring 的方式分別賦值給予變數。
const stringFactory = (str) => [str.toUpperCase(), str.toLowerCase()]
[upper, lower] = stringFactory('Hello World');
// upper = 'HELLO WORLD'
// loewr = 'hello world'
Spread & Destructuring Objects
ES2018 開始,不僅能夠針對 Array 進行 Spread 及 Destructuring,JS 對於 Object 也支援 Spread 及 Destructuring。
Spread
可以用於合併物件的屬性,例如想要把各學習階段物件的知識技能傳承下去:
const elementrySchool = {read: 6, calculate: 3}
const juniorHighSchool = {readEng: 3, calculate: 5}
const seniorHighSchool = {readEng: 7, calculate: 9, coding: 2}
let now = {...elementrySchool, ...juniorHighSchool, ...seniorHighSchool}
// { read: 6, calculate: 9, readEng: 7, coding: 2 }
如果有相同名稱的 properties 則順序很重要,後進行 destructuring 的值會覆寫先前的值。
let now = {...juniorHighSchool, ...seniorHighSchool, ...elementrySchool}
// { readEng: 7, calculate: 3, coding: 2, read: 6 }
Spread 也可以用於 shallow copy 的方式產生新的 Object:
const slime = {color: 'blue', hp: 3, mp: 1}
const redSlime = {...slime, color: 'red'}
// { color: 'red', hp: 3, mp: 1}
Destructuring
這是使用 Destructuring 在語法上比較特別的地方,當 slime Object 有提供 hp property 時,會使用該 property 作為 healthPoint variable 的數值,否則就會以預設值 5 作為 healthPoint 的數值。
來自解構對象的名稱要在冒號之前,賦值的變數值名稱則是在冒號之後:
const slime = {color: 'blue', hp: 3, mp: 1}
let {hp: healthPoint = 5, fast = 3} = slime
// healthPoint = 3
// fast = 3
此外如果 Destructuring 右側的物件有同名的 Property 與左側解構的名稱相同,則會自動以右側解構的值進行覆寫:
const slime = {color: 'blue', hp: 3, mp: 1, fast: 5}
let {hp: healthPoint = 5, fast = 3} = slime
// healthPoint = 3
// fast = 5
對於 null destructuring 以及 nested 的處理都如同 Array 的支援 🙄
Real Example Code
用途是從 localStorage 將資料讀回,並寫回 Vue 的 Data 之中,其中因為 wrongs 儲存的是 Set,所以另以賦值的方式處理。
/*
appSavings in localStorage
appSavings | {"corrects":[119,309],"wrongs":[800,1069,489],"completed":5}
*/
if (localStorage.appSavings !== undefined) {
const appSavings = JSON.parse(localStorage.appSavings);
({ corrects: this.corrects, completed: this.completed } = appSavings);
this.wrongs = new Set(appSavings.wrongs);
}
ECMA JavaScript ES20XX 系列筆記
參考資料
ES20XX
JavaScript: What’s new in ECMAScript 2019 (ES2019)/ES10?
ES2020 中 Javascript 10 個你應該知道的新功能
Node.js Dancing with ES20XX
查詢 Node.js 各版本對於 Ecma JavaScript 的支援情況。目前主要使用的 Node.js 12.10 對於 ES2019 以前都有相當高的支援情況,所以使用新 Feature 無煩惱。