最近可能會很常看到程式碼中常常出現...這種三個句點的運算子,他有兩種功能,一種是當做Spread運算子,另一種是Rest參數,這篇文章先來探索一下Spread運算子的功能,以及他的威力所在。

在ES6時有了array相關的spread語法,而到ES2016+進而支援了object的spread,現在最新版的瀏覽器以及NodeJS中皆可以不需要進行轉義就可以使用。

Spread運算子我們可以簡單的想成是array或者object的展開。我們透過一個簡單的例子來看看

合併陣列

我們想要合併兩個陣列,如果我們不使用spread運算子

const odd = [1, 3, 5, 7, 9]; const even = [2, 4, 6, 8]; const concat = [odd, even]; // [[1, 3, 5, 7, 9], [2, 4, 6, 8]]

可以發現concat變成了二維的陣列,並不是我們想要的結果,我們需要將他攤平。
我們可以改為使用spread來幫我們做到這件事。

const odd = [1, 3, 5, 7, 9]; const even = [2, 4, 6, 8]; const concat = [...odd, ...even]; // [1, 3, 5, 7, 9, 2, 4, 6, 8]

沒錯,結果正確。

我們可以把spread運算子想成是一個一個取出array中的元素,做到類似下面這段程式碼的效果。

const odds = [1, 3, 5, 7, 9]; const concat = [] for(odd of odds) { concat.push(odd); }

數學運算

我們拿Math.max這個函數來當做範例,他的功能是能夠從傳入的參數中找到最大值,例如

const max = Math.max(1, 3, 5, 4, 2); console.log(max); // 5

Math.max並無法處理array,他僅能處理他的參數們,這時候spread又派上用場了

const arr = [1, 3, 5, 4, 2]; let max = Math.max(arr); // Error: max=Nan max = Math.max(...arr); // Successful: max=5

複製陣列

想想下面面試常常考的陷阱題

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

因為JS的特性,當y=x時,實際上是將y的記憶體位址指向x,因此其實x和y是相同的我們可以通過x===y來驗證這件事。

如果我們想要完整的複製一份x到y,而這兩個彼此間是獨立的,那我們該如何做呢?

傳統的做法上,我們會呼叫Array.prototype.slice這個函式,他的功能是建立一個新的array,並且裁切我們想要的部分,如果我們整段都不裁切,那就是做到了複製的功能。

const x = [0, 1, 2]; const y = x.slice(); y[0] = 3; console.log(x[0]); // 0 console.log(y[0]); // 3

而用spread我們能夠更簡單的做到這件事

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

Object spread

Object spread其實與array十分相似,現今頁面的狀態State常常都是使用一個Object來管理,為了讓State可以Trace,我們在修改狀態時常常要做的就是複製一份新的Object,僅對其需要修改的部分修改完後再覆蓋回去,做到Pure的目的,此時Object spread就能夠派上很大的用場。

const OldState = { login: false, username: "", visitedTimes: 0, }; const NewState = { ...OldState, visitedTimes: OldState.visitedTimes+1, }

References:
1. JavaScript ES6— The Spread Syntax (…)
2. MDN: Spread syntax