Array.prototype.reduce 實用指南

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 的升序進行排列,totaltype 不定~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 的對象形式,更利於進行以後的操做。那咱們就以轉換爲 keyidvalue 是其餘屬性的對象做爲目標吧!

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,避免寫出難以維護的代碼,值得每一位同窗思考。

感謝各位看官大人看到這裏,知易行難,但願本文對你有所幫助~謝謝!

相關文章
相關標籤/搜索