1. 程式人生 > >陣列中的reduce 函式理解

陣列中的reduce 函式理解

第一次見到reduce 是在js 的高階程式設計中,它的意思是把一個數組減少為一個數,舉的例子是陣列中元素的求和。它接受一個函式作為引數,函式又有兩個引數,一個是prev, 前一個值,一個是next, 後一個值,然後函式體就是返回相加的值。

let array = [1, 3, 5];
let sum = array.reduce((prev, next) => {
  return prev + next;
})

console.log(sum);
  我對reduce 的理解也僅限於此,只停留在了表面,當然,除了這個例子之後,我也不會用reduce. 今天在讀js函數語言程式設計相關書籍的時候,又遇到reduce, 仔細讀了幾遍,加深了理解,大體上懂了它的原理和用法。   reduce 確實是把陣列減少為一個值,也是接受一個函式作為引數,但它還有一個可選的第二個引數。對函式接受的兩個引數的理解也有偏差,第一個引數準確來講應該是個累計值,第二個引數應該是陣列的每一個項的值。還是陣列的求和為例,我們完全可以不用recude, 直接迴圈遍歷陣列就可以。那麼我們該怎麼做呢?   先宣告一個變數,來儲存求和後的值。
let sum = 0;
  然後迴圈遍歷陣列的每一項,和sum 進行相加
for (let index = 0; index < array.length; index++) {
  const element = array[index];
  sum = sum + element;
}

  完全沒有問題,可以求出陣列中的元素的和。陣列元素的求和應該都是這樣的步驟,我們嘗試把這個步驟封裝一下, 先直接定義一個函式把所有步驟包含起來, 只把console.log(sum) 變成return sum;

function reduce () {

  let sum 
= 0; for (let index = 0; index < array.length; index++) { const element = array[index]; sum = sum + element; } return sum; }

  現在來看封裝的函式,可以發現有幾個問題:

  1,let sum = 0 不太合適,在函式中固定一個變數的值,不具有靈活性。這個很簡單,可以宣告一個變數,讓sum 等於傳遞進行的值。如果沒有,可以默為0 , 變數為initValue;

  2,這個問題也很簡單地,就是要遍歷的陣列,要把陣列傳遞進來,所以要接受一個數組引數,用來進行遍歷。   3,這個問題可能不太好理解,但也是最關鍵的。第三個問題是在sum = sum + element;sum + element是這個函式要做的事情,如果不指定,這個reduce 函式只能做求和運算。我們想讓這個函式更為通用,函式要做的事情就要讓使用者進行指定。要做的事情,在js 中,可以用函式進行表示,所以接受一個函式做為引數,這個函式要接受兩個引數sum, elemnet, 然後在函式體中指定這個函式要做什麼事情。由於sum + element 的值要賦值為sum, 所以這個函式還要有返回值。
function
reduce (array, fn, initValue) { let sum ; initValue ? (sum =initValue): (sum = 0); // 然後迴圈遍歷陣列的每一項,和sum 進行相加 for (let index = 0; index < array.length; index++) { const element = array[index]; sum = fn(sum, element); } return sum; }

  呼叫我們自己封裝的reduce 時行陣列的求和

let result = reduce(array, (sum, element) => sum  + element);

  現在我們來對比原生的呼叫方式和自己封裝的方式?可以發現沒有本質不同。唯一的不同可能是我們的第一個引數是陣列,而原生沒有,這是因為原生的方法是定義在陣列原型上,所 以沒有接受陣列作為引數,對於理解reduce 函式來說,這沒有什麼本質的不同。通過封裝的過程,我們更能明白接受的函式的引數的意思。這個函式至少要接受兩個引數,第一個引數的真正意義應該是呼叫函式所返回的值,由於在第一個呼叫函式之前,沒有返回值,所以我們可以給它賦初值,或通過第三個引數,或直接調為0。 第二個引數,就是陣列的每一項,只有不停的遍歷陣列中的每一項,最終才能把陣列變成一個值。其實初值還有一個更好的辦法,如果沒有傳遞進來,可以取陣列的第一項作為初始值。最終的函式可能如下:

const reduce = (array, fn, initialValue) => {
  let sum;
  if (initialValue) {
    sum = initialValue;
    for (const value of array)  // 這裡用了es6 在for of 
      sum = fn(sum, value)
  }
  else {
    sum = array[0];
    for (let i = 1; i < array.length; i++)
      sum = fn(sum, array[i])
  }
  return sum;
}

  通過以上分析,我們可以看到,reduce函式真正的核心在於傳遞進去的函式。正確的使用reduce 就是要正確的寫好這個函式,通常這個函式要滿足一下,幾點要求。

  1, 這個函式至少要接受兩個引數進行計算,一個引數是累計值,一個引數是陣列的每一個元素

  2, 這個函式必須要有返回值,因為要用它進行下一步的運算,並且,必須返回一個由引數進行計算的得到結果值,最後返回的值,還是要和陣列中的元素型別相同,這還是因為它要進行下一步的運算。

  3, 初始的結果值,可以由第三個引數進行傳遞,也可以不傳,如果不傳的話,初始的累計值預設為第一個引數。