hello~親愛的看官老爺們你們好~最近由於工(lan)做(ai)繁(fa)忙(zuo),出產的文章多以譯文爲主,以前翻譯了《如何在 JavaScript 中更好地使用數組》一文,發現很多同窗對 Array.prototype.reduce
不太熟悉,而我正好在這方面有一點積累,在此分享給你們。前端
Array.prototype.reduce
算是 JavaScript 數組中比較難用但又特別強大的方法,本文以實用爲主,經過例子展現如何使用這個方法,但並不深挖這個方法的本質(深刻的話涉及到不少函數式編程相關的知識)~如下是正文。編程
Array.prototype.reduce
的簡單介紹
reduce()
方法對累加器和數組中的每一個元素(從左到右)應用一個函數,將其簡化爲單個值。後端
上述是 MDN對該方法的描述,方法的語法是: arr.reduce(callback[, initialValue])
。callback
接受四個參數,分別是:accumulator
,累加器累加回調的返回值; currentValue
,數組中正在處理的元素;currentIndex(可選)
,數組中正在處理的當前元素的索引;array(可選)
,調用 reduce()
的數組。initialValue
爲可選參數,做爲第一次調用 callback
函數時的第一個參數的值。方法的返回值是函數累計處理的結果。數組
一股腦介紹完以後,估計很多同窗都是比較懵的。其實這個方法並不難理解的,正如它名字所示,抓住它的核心:聚合。通常而言,若是須要把數組轉換成其餘元素,如字符串、數字、對象甚至是一個新數組的時候,若其餘數組方法不太適用時,就能夠考慮 reduce
方法,不熟悉這個方法的同窗,儘管拋開上面的語法, 記住方法的核心是聚合便可。函數式編程
下文的例子都用到如下數組,假設經過接口獲取到以下的數據體:函數
[{
id: 1,
type: 'A',
total: 3
}, {
id: 2,
type: 'B',
total: 5
}, {
id: 3,
type: 'E',
total: 7
},...]
複製代碼
數據體是按照 id
的升序進行排列,total
與 type
不定~post
根據上述數據體,咱們一塊兒來作第一個小需求,統計 total
的總和。若是不用 reduce
,其實也不難:spa
function sum(arr) {
let sum = 0;
for (let i = 0, len = arr.length; i < len; i++) {
const { total } = arr[i];
sum += total;
}
return sum;
}
複製代碼
這個函數能夠完成上述需求,但咱們精確地維護了數組索引,再精確地處理整個運算過程,是典型的命令式編程。上文說起,只要涉及將數組轉換爲另外的數據體,就可使用 reduce
,它能夠這樣寫:prototype
arr.reduce((sum, { total }) => {
return sum + total;
}, 0)
複製代碼
這樣就完成了~sum
是此前累加的結果,它的初始值爲 0。每次將此前的累計值加上當前項的 total
爲這次回調函數的返回值,做爲下次執行時 sum
的實參使用。看起來比較繞,能夠參考下面的表格:翻譯
輪次 | sum |
total |
返回值 |
---|---|---|---|
1 | 0(初始值) | 3 | 3 |
2 | 3 | 5 | 8 |
3 | 8 | 7 | 15 |
... | ... | ... | ... |
如此是否是清晰了不少?前一次的返回值就是後一次 sum
的值,如此類推,最後累積出總和,將數組聚合成了數字。
下一個需求是將數組的每項轉換爲固定格式的字符串(如第一項轉換爲 id:1,type:A;
),每項直接以分號做爲分隔。通常來講,數組轉爲字符串,join
方法是不錯的選擇,但並不適用於須要精確控制或數組的項比較複雜的狀況。在本例中,join
方法是達不到咱們想要的效果的。
使用 for
循環固然能夠解決問題,但 reduce
也許是更好的選擇,代碼以下:
arr.reduce((str, { id, type }) => {
return str + `id:${id},type:${type};`;
}, '')
複製代碼
有了聚合爲數字的例子,此次你能在腦海中模擬出執行的過程麼?如下也是前三項的執行過程:
輪次 | str |
id |
type |
返回值 |
---|---|---|---|---|
1 | ''(初始值) | 1 | 'A' | 'id:1,type:A;' |
2 | 'id:1,type:A;' | 2 | 'B' | 'id:1,type:A;id:2,type:B;' |
3 | 'id:1,type:A;id:2,type:B;' | 3 | 'E' | 'id:1,type:A;id:2,type:B;id:3,type:E;' |
... | ... | ... | ... | ... |
有了前面的一點基礎,能夠作複雜一點的聚合了。上面的數據體是比較典型的後端接口返回結果,但對於前端來講,轉換成 key
value
的對象形式,更利於進行以後的操做。那咱們就以轉換爲 key
是 id
,value
是其餘屬性的對象做爲目標吧!
function changeToObj(arr) {
const res = {};
arr.forEach(({ id, type, total }) => {
res[id] = {
type,
total
};
})
return res;
}
複製代碼
如上所示,這個函數能夠很好地完成咱們的目標。但略顯囉嗦,記住:只要目標是將數組聚合爲惟一的元素時,均可以考慮使用 reduce
。這個例子剛好符合:
arr.reduce((res, { id, type, total }) => {
res[id] = {
type,
total
};
return res;
}, {})
複製代碼
res
是最後返回的對象,經過遍歷數組,不斷往裏面添加新的屬性與值,最後達到聚合成對象的目的,代碼仍是至關簡潔有力的。
最後,對於不熟悉這個方法的同窗,不妨練習一下,將數據體轉換爲一個字符串數組,數組每一項爲原數組 type
的值。
以上就是本文的所有內容,這裏稍微小結一下 reduce
的優缺點~原則上說,只要是將數組聚合爲惟一的元素時,均可以實現它。同時,它在函數式編程中有一席之地,也是聲明式編程的典型例子。這也意味着它不容易掌握,若是熟悉 reduce
方法,寫出來的代碼可讀性強,十分優雅。但在不熟悉的同窗眼裏,這就是徹徹底底的天書了。如何更好地使用 reduce
,避免寫出難以維護的代碼,值得每一位同窗思考。
感謝各位看官大人看到這裏,知易行難,但願本文對你有所幫助~謝謝!