數組中的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, 初始的結果值,可以由第三個參數進行傳遞,也可以不傳,如果不傳的話,初始的累計值默認為第一個參數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM