【譯】10分鐘學會reduce

原文連接:yazeedb.com/posts/learn…
原做者:Yazeed Bzadough前端

但願這能夠減小你的困惑

根據我學習和教學JavaScript的經驗,reduce是最難掌握的概念之一。在這篇文章裏,我將嘗試解決一個核心問題...git

reduce 是什麼,爲何它叫 reduce程序員

reduce有不少名字

根據 Wikipedia, 其中一些包括github

  • Reduce
  • Fold
  • Accumulate
  • Aggregate
  • Compress

它們都暗示了核心思想。將結構分解爲單個值編程

Reduce - 一個能夠將列表摺疊成任意數據類型的函數redux

這就像摺疊一個盒子!使用reduce你能夠將數組[1,2,3,4,5]每一項相加獲得數字15數組

folding-box

新手方式

一般,你須要循環才能將列表」摺疊「成數字函數式編程

const add = (x, y) => x + y;
const numbers = [1, 2, 3, 4, 5];
let total = 0;

for(let i = 0; i < numbers.length; i++) {
    total = add(total, numbers[i]);
}
console.log(total); // 15
複製代碼

老司機方式

可是使用reduce你能夠插入你的add函數,就能夠爲你處理循環了函數

const add = (x, y) => x + y;
const numbers = [1, 2, 3, 4, 5];

const total = numbers.reduce(add);
// 15
複製代碼

你逐項地摺疊1-5便可得到15工具

folding-box

三巨頭

在深刻探討以前,我認爲先分析reduce和它著名的同伴-mapfilter很重要。它們嚴重掩蓋了reduce的光輝,讓它看起來很古怪。

creepy-reduce

儘管它們各自很受歡迎,但結合使用這三個巨人可讓你隨意操做列表!

the-big-three

這裏咱們作個假設,僞裝JavaScript不能使用循環,遞歸,或者像forEachsomefind等數組方法。只剩下mapfilterreduce三個方法。 可是咱們做爲程序員的工做沒有改變,咱們的應用程序中仍然須要三種類型的功能。

  1. 轉換列表
  2. 篩選列表
  3. 將列表轉換爲其它數據類型(數字,字符串,布爾值,對象等)

讓咱們看看咱們剩下的工具-map,filterreduce-如何應對這個挑戰。

Array.map 轉換列表

簡而言之,將列表轉換成其餘列表是前端開發。所以map涵蓋了你的大部分列表工做。

假設咱們的應用程序調用了一個用戶列表的API,而且咱們須要在屏幕上顯示每一個用戶的用戶名。只需建立一個返回用戶用戶名的函數。

const getUserName = (user) => user.name;
複製代碼

而後插入map針對整個列表列表運行。

users.map(getUserName);
// ['Marie', 'Ken', 'Sara', 'Geoff', ...]
複製代碼

Array.filter 判斷列表

若是你想刪除某些項而生成一個新列表,例如用戶搜索他們的聯繫人列表?只需建立一個基於它的輸入返回truefalse的函數。

const isEven = (x) => x % 2 === 0;
複製代碼

而後插入filter針對整個列表運行。

const numbers = [1, 2, 3, 4, 5];
numbers.filter(isEven);
// [2, 4]
複製代碼

Array.reduce 完成全部這些工做,甚至更多

mapfilter還不夠時,你須要你們夥。map/filter能作的工做,reduce都能作,還有其餘任何涉及遍歷數組的。

reduce-will-take-this

例如,你將如何計算用戶的總年齡?咱們的用戶的年齡是25,22,29和30。

const users = [
  { name: 'Marie', age: 25 },
  { name: 'Ken', age: 22 },
  { name: 'Sara', age: 29 },
  { name: 'Geoff', age: 30 }
];
複製代碼

mapfilter只能返回數組,可是咱們須要的是一個number

users.map(?);
users.filter(?);

// Nope! I need a number, not arrays.
複製代碼

若是咱們有循環,咱們將遍歷用戶列表並經過一個計數器統計他們的年齡! 好吧,若是我告訴你使用reduce會更簡單些?

users.reduce((total, currentUser) => total + currentUser.age, 0);
// 106
複製代碼

fallout-hold-up

打印下log

我認爲要理解它一個簡單的方法就是每一步都用console.log打印出來

const users = [
  { name: 'Marie', age: 25 },
  { name: 'Ken', age: 22 },
  { name: 'Sara', age: 29 },
  { name: 'Geoff', age: 30 }
];

const reducer = (total, currentUser) => {
  console.log('current total:', total);
  console.log('currentUser:', currentUser);

  // just for spacing
  console.log('\n');

  return total + currentUser.age;
};

users.reduce(reducer, 0);
複製代碼

這裏有一張Chrome開發工具的截圖。

reduce-screenshot-1

分解

如你所見,Array.reduce有兩個參數

  1. reducer
  2. 初始值(可選)

reducer是完成全部工做的函數。當reduce循環遍歷你的列表時,它提供兩個參數給你的reducer

  1. 累加器
  2. 當前值

當前值不用說,就像你在常規循環中使用array[i]同樣。不過,累加器是一個聽起來很嚇人的計算機科學術語,實際上很簡單。

累加器是最終返回的值

當你循環遍歷用戶列表時,你如何跟蹤它們的總年齡?你須要一些計數器變量來保存它。那就是累加器。它將做爲最終值在reduce完成後輸出。

在循環的每一步,它提供最後的累加器和當前值給你的reducer。不管reducer返回什麼都將成爲下一個累加器。當列表遍歷完成而且你獲得一個reduce後的單一的值, 循環結束。

reduce-screenshot-1

初始值是可選的

reduce的第二個參數初始值是可選的。若是不提供,默認爲列表的第一個元素。

若是你要對純數字求和,那很好。

[1, 2, 3].reduce((total, current) => total + current);
// 6
複製代碼

可是若是你使用對象或數組會中斷,由於你不該該將這些東西加起來。

[{ age: 1 }, { age: 2 }, { age: 3 }].reduce((total, obj) => total + obj.age, 0);

// 6
// Initial value fixes it.
// 0 + 1 + 2 + 3 = 6
複製代碼

讓咱們從新建立一個reduce

我不能理解我沒法創造的東西-理查德·費曼(Richard Feynman)

但願到目前爲止,我已經對你有所幫助。如今是時候編寫本身的reduce函數來真正錘鍊本身了。

它將是一個有三個參數的函數。

  1. reducer
  2. 初始值
  3. 要操做的數組

對於這個demo,初始值不是可選的

const reduce = (reducer, initialValue, array) => {
  let accumulator = initialValue;

  for (let i = 0; i < array.length; i++) {
    const currentItem = array[i];
    accumulator = reducer(accumulator, currentItem);
  }

  return accumulator;
};
複製代碼

僅需10行代碼,6個關鍵步驟。我將一步一步說明。

  1. 定義reduce及其三個參數。
  2. 使用接收到的初始值參數初始化初始值(initialValue)。該變量每一個循環都將改變。
  3. 開始遍歷數組。
  4. 捕獲循環中數組的當前值(currentItem)。
  5. 調用reducer並將accumulatorcurrentItem傳入,將結果做爲新的accumulator保存。
  6. 當循環結束而且accumulator更改完成,將其返回。

多樣的歷史

我想談談更多關於 reducereducers 的歷史,但不大肯定應該放在哪裏。儘管如此,它仍是頗有趣的!

reducers是古老的

redux-did-not-invent-reducers

Redux爲JavaScript開發人員帶來了reducers的炫酷用法。但它沒有發明他們。實際上不清楚是誰創造了該術語,但這裏是我參考的一些參考文獻。

遞歸理論(1952)

1952年出版的 這本書 從形而上學的角度討論了reduce,將其稱爲fold。

Lisp程序員手冊(1960)

1960出版的《Lisp程序員手冊》中有一章是關於reduce函數的。

函數式編程概論(1988)

1988年出版的 這本書 談論如何使用 reduce 將列表轉換爲其餘值。 底線是一個古老的話題。你對計算機科學的研究越多,你就越意識到咱們正在從新包裝幾十年前發現的概念。

你對計算機科學的研究越多,你就越意識到咱們正在從新包裝幾十年前發現的概念。 — Yazeed Bzadough (@yazeedBee) October 13, 2019

爲你準備的練習

爲了節省時間,咱們就在這裏結束。我但願至少已暗示這reduce除求和以外的強大功能。

若是您有興趣,請嘗試這些練習(盡請關注後續文章)

  1. 使用 reduce 從新實現 Array.map 函數。
  2. 使用 reduce 從新實現 Array.filter 函數。
  3. 使用 reduce 從新實現 Array.some 函數。
  4. 使用 reduce 從新實現 Array.every 函數。
  5. 使用 reduce 從新實現 Array.find 函數。
  6. 使用 reduce 從新實現 Array.forEach 函數。
  7. 使用 reduce 將數組轉換爲對象。
  8. 使用 reduce 將二維數組轉換爲一維數組(flat)。

傳送門

【譯】使用reduce製做的10個JavaScript實用函數

相關文章
相關標籤/搜索