深刻理解全能的 Reducer

翻譯: 劉小夕javascript

原文連接:css-tricks.com/understandi…css

更多文章可戳: github.com/YvetteLau/B…html

有一些小夥伴,對JavaScript的 reduce 方法還不夠理解,咱們來看下面兩段代碼:java

const nums = [1, 2, 3];
let value = 0;

for (let i = 0; i < nums.length; i++) {
    value += nums[i];
}
複製代碼
const nums = [1, 2, 3];
const value = nums.reduce((ac, next) => ac + next, 0);
複製代碼

這兩段代碼在功能上是等價的,都是數組中全部數字的總和,可是它們之間有一些理念差別。讓咱們先研究一下 reducer,由於它們功能強大,並且在編程中很重要。有成百上千篇關於 reducer 的文章,最後我會連接我喜歡的文章。git

reducer 是什麼

要理解 reducer 的第一點也是最重要的一點是它永遠返回一個值,這個值能夠是數字、字符串、數組或對象,但它始終只能是一個。reducer 對於不少場景都很適用,可是它們對於將一種邏輯應用到一組值中並最終獲得一個單一結果的狀況特別適用。github

另外須要說明:reducer 本質上不會改變你的初始值;相反,它們會返回一些其餘的東西。shell

讓咱們回顧一下第一個例子,這樣你就能夠看到這裏發生了什麼,一塊兒看一下下面的gif:編程

觀看gif也許對咱們全部幫助,不過仍是要回歸代碼:數組

const nums = [1, 2, 3];
let value = 0;

for (let i = 0; i < nums.length; i++) {
    value += nums[i];
}
複製代碼

數組 nums ([1,2,3]) ,數組中的每一個數字的第一個值將被添加到 value (0)。咱們遍歷數組並將其每一項添加到 value函數

讓咱們嘗試一下不一樣的方法來實現此功能:

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = function (acc, item) { 
    return acc + item;
}

const total = nums.reduce(reducer, initialValue);
複製代碼

如今咱們有了相同的數組,但此次咱們不會改變初始值(即前段代碼中的 value)。這裏,咱們有一個僅在開始時使用的初始值。接下來,咱們能夠建立一個函數,它接受一個累加器(acc)和一個項(item)。累加器是在上一次調用中返回的累積值(或者是 initialValue),是下一個回調的輸入值。在這個例子中,你能夠把它想象成一個滾下一座山的雪球,當它以每個吃過的值的大小增加時,它會吃掉它路徑中的每一個值。

咱們將使用 .reduce() 來接收這個函數並從初始值開始。可使用箭頭函數簡寫:

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = (acc, item) => { 
    return acc + item;
}

const total = nums.reduce(reducer, initialValue);
複製代碼

進一步縮短代碼長度,咱們知道箭頭函數,在沒有 {} 時,默認 return;

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = (acc, item) => acc + item;

const total = nums.reduce(reducer, initialValue);
複製代碼

如今咱們能夠在調用它的地方應用這個函數,也能夠直接設置初始值,以下:

const nums = [1, 2, 3];

const total = nums.reduce((acc, item) => acc + item, 0);
複製代碼

累加器多是一個使人生畏的術語,因此當咱們在回調調用上應用邏輯時,你能夠將它想象成數組的當前狀態。

調用棧

若是不清楚發生了什麼,讓咱們記錄下每次迭代的狀況。reduce 使用的回調函數將針對數組中的每一個項運行。下面的演示將有助於更清楚地說明這一點。我使用了一個不一樣的數組([1,3,6]),由於數字與索引相同可能會使人困惑。

const nums = [1, 3, 6];

const reducer4 = function (acc, item) { 
    console.log(`Acc: ${acc}, Item: ${item}, Return value: ${acc + item}`);
    return acc + item;
}
const total4 = nums.reduce(reducer4, 0);
複製代碼

當咱們執行這段代碼時,咱們會在控制檯看到如下輸出:

Acc: 0, Item: 1, Return value: 1
Acc: 1, Item: 3, Return value: 4
Acc: 4, Item: 6, Return value: 10
複製代碼

下面是一個更直觀的分解:

  1. 累加器(acc)從初始值(initialValue):0 開始的
  2. 而後第一個 item是1,因此返回值是1(0+1=1)
  3. 1在下次調用時成爲累加器
  4. 如今咱們累加器是1(acc),item (數組的第二項)是3
  5. 返回值變爲4(1+3=4)
  6. 4在下次調用時成爲累加器,調用時的下一項 item 是6
  7. 結果是10(4+6=10),是咱們的最終值,由於6是數組中的最後一項

簡單示例

既然咱們已經掌握了這一點,那麼讓咱們來看看 reducer 能夠作的一些常見和有用的事情。

咱們有多少個X?

假設您有一個數字數組,而且但願返回一個報告這些數字在數組中出現的次數的對象。請注意,這一樣適用於字符串。

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82];

const result = nums.reduce((tally, amt) => {
    tally[amt] ? tally[amt]++ : tally[amt] = 1;
    return tally;
}, {});

console.log(result);
//{ '1': 1, '3': 2, '4': 1, '5': 2, '6': 1, '82': 2 }

複製代碼

最初,咱們有一個數組和將要放入其中的對象。在 reducer 中,咱們首先判斷這個item是否存在於累加器中,若是是存在,加1。若是不存在,添加這一項並設置爲1。最後,請返回每一項出現的次數。而後,咱們運行reduce函數,同時傳遞 reducer 和初始值。

獲取一個數組並將其轉換爲顯示某些條件的對象

假設咱們有一個數組,咱們但願基於一組條件建立一個對象。reduce 在這裏很是適用!如今,咱們但願從數組中任意一個數字項建立一個對象,並同時顯示該數字的奇數和偶數版本。

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82];

// we're going to make an object from an even and odd
// version of each instance of a number
const result = nums.reduce((acc, item) => {
  acc[item] = {
    odd: item % 2 ? item : item - 1,
    even: item % 2 ? item + 1 : item
  }
  return acc;
}, {});

console.log(result);
複製代碼

控制檯輸出結果:

{ '1': { odd: 1, even: 2 },
  '3': { odd: 3, even: 4 },
  '4': { odd: 3, even: 4 },
  '5': { odd: 5, even: 6 },
  '6': { odd: 5, even: 6 },
  '82': { odd: 81, even: 82 } 
}
複製代碼

當咱們遍歷數組中的每一項時,咱們爲偶數和奇數建立一個屬性,而且基於一個帶模數運算符的內聯條件,咱們要麼存儲該數字,要麼將其遞增1。模算符很是適合這樣作,由於它能夠快速檢查偶數或奇數 —— 若是它能夠被2整除,它是偶數,若是不是,它是奇數。

其它資源

在頂部,我提到了其餘一些便利的文章,這些文章有助於更熟悉 reducer 的做用。如下是個人最愛:

  1. MDN文檔對此很是有用。說真的,這是他們最好的帖子之一,他們也更詳細地描述了若是你不提供一個初始值會發生什麼,咱們在這篇文章中沒有提到。
  2. Coding Train
  3. A Drip of JavaScript

謝謝各位小夥伴願意花費寶貴的時間閱讀本文,若是本文給了您一點幫助或者是啓發,請不要吝嗇你的贊和Star,您的確定是我前進的最大動力。 github.com/YvetteLau/B…

關注公衆號,加入技術交流羣

相關文章
相關標籤/搜索