壹 ❀ 引面試
稍微有了解JavaScript數組API的同窗,對於reduce方法至少有過一面之緣,也許是for與forEach太強大,或者filter,find很實用,在實際開發中我至始至終沒使用過reduce方法一次。很巧的是今天再刷面試題的過程當中,遇到了一題關於數組操做的的題,相關解析中有人使用到了reduce方法,好吧我認可我看着有點茫然,由於我從未正眼過它,那麼今天就給彼此一首歌的時間,讓咱們好好了解你,關於reduce本文開始。數組
貳 ❀ 關於reduce函數
一個完整的reduce方法應該是這樣:spa
array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)
它由一個回調函數與一個初始值組成,其中回調函數接受四個參數,咱們先解釋回調函數形參與initialValue的含義:翻譯
1.initialValue [ɪˈnɪʃl] [ˈvæljuː] 初始值code
initialValue 表示reduce方法第一次執行時的初始值,是一個可選值。blog
2.accumulator [əˈkjuːmjəleɪtər] 累加器;積聚者索引
accumulator 正如翻譯的那樣,它是 reduce 方法屢次執行的累積結果,accumulator 的初始值分兩種狀況:ip
如有提供 initialValue 初始值,第一次循環時 accumulator 的值便爲 initialValue,後續循環時 accumulator 爲上次循環的返回值。開發
若未提供initialValue,第一次循環時 accumulator 的值爲數組第一項arr[0],後續循環時爲上次循環的返回值。
3.currentValue [ˈkɜːrənt] [ˈvæljuː] 當前值
這個應該不難理解,數組循環當前處理的值。currentValue 的初始值也受到initialValue的影響:
如有提供 initialValue 初始值,第一次循環currentValue 的值爲數組第一項arr[0],後續變化隨索引遞增變化。
若未提供initialValue,第一次循環因爲arr[0]成了accumulator 的值,因此currentValue 只能從arr[1]開始,後續變化隨索引遞增。
4.currentIndex
數組循環當前處理值的索引,currentValue 與 currentIndex是同步變化的。
5.array
當前正在被循環的數組。
說的有點糊塗?不要緊,咱們經過例子按部就班的來理解,加深這幾個參數的印象。先看第一個例子:
let arr = ['e', 'l', 'l', 'o']; arr.reduce((accumulator, currentValue, currentIndex, array) => { console.log(accumulator, currentValue, currentIndex, array); });
咱們直接打印出四個參數,咦?爲何 accumulator第一次循環是e,後續循環怎麼都是undefined了?
前面說了,因爲reduce方法沒有提供初始值,因此第一次循環數組的第一項做爲了reduce方法的初始值,後續循環中因爲沒 return操做,致使accumulator拿不到上次返回值,因此就是undefined了。
咱們在console後面加上return操做,再看:
return accumulator+currentValue;
這不就有值了嗎,因此使用reduce方法得記住,因爲reduce是一個對數組累積操做的方法,在使用中必定得記得加return返回你但願累積操做的數據。
那也不對啊,我數組明明有四項,照輸出來看reduce方法怎麼只執行了三次?
這是由於咱們沒提供初始值 initialValue ,致使reduce方法將數組的第一項做爲了初始值,因此循環第一次是從數組第二項開始的,咱們嘗試給reduce添加一個默認值:
let arr = ['e', 'l', 'l', 'o']; arr.reduce((accumulator, currentValue, currentIndex, array) => { console.log(accumulator, currentValue, currentIndex, array); return accumulator+currentValue; },'h');
能夠看到有了默認值,數組第一次循環是從索引 0 開始,完完整整的執行了四次。
也不對啊,accumulator不是循環的累加值嗎,執行完畢了怎麼顯示的是 hell,o怎麼沒加進去?這不是由於我console寫在了return前面了麼(我故意的),執行完最後一次跳出循環,reduce方法會返回最終的執行結果,咱們用一個變量來保存試試,像這樣:
let arr = ['e', 'l', 'l', 'o']; let result = arr.reduce((accumulator, currentValue, currentIndex, array) => { return accumulator+currentValue; },'h'); console.log(result);//hello
看,這不就是一個完整的單詞 hello了;
其實對於reduce讓人疑惑的無非就是initialValue與accumulator,currentValue的關係,這裏咱們作個小總結:
若是reduce有提供初始值,則循環從索引0開始,此時accumulator就是initialValue,currentValue值就是arr[0];若是reduce未提供初始值,則arr[0]做爲初始值賦予給accumulator,循環從索引1開始,currentValue值就是arr[1]了;
叄 ❀ reduce做用
那麼到這裏咱們詳細介紹了reduce方法的參數與執行規則,瞭解了這些,咱們能夠用reduce方法作些什麼呢?
1.數組求和
reduce方法本意就是用來記錄循環的累積結果,用於數組求和是最合適不過了。好比咱們要求數組 [1,2,3,4] 的元素之和,用forEach你得這樣寫:
let total = 0; [1, 2, 3, 4].forEach(item => total += item); console.log(total); //10
但經過reduce方法就簡單的多,咱們能夠這麼寫:
let total = [1, 2, 3, 4].reduce((accumulator, current) => accumulator += current); // 10
假設咱們但願求數字90與數組 [ 1,2,3,4] 元素的和呢,那就這麼寫:
let total = [1, 2, 3, 4].reduce((accumulator, current) => accumulator += current, 90); // 100
2.數組去重
好比咱們要將數組 [1,2,2,4,null,null] 去除掉重複項,用filter能夠這樣作:
let arr = [1, 2, 2, 4, null, null].filter((item, index, arr) => arr.indexOf(item) === index); // [1,2,4,null]
固然單說實現使用 new Set 更簡單:
let arr = [...new Set([1, 2, 2, 4, null, null])]; // [1,2,4,null]
如今咱們知道了reduce方法,其實也能夠經過reduce去重,像這樣:
let arr = [1, 2, 2, 4, null, null].reduce((accumulator, current) => { return accumulator.includes(current) ? accumulator : accumulator.concat(current); }, []);
3.數組降維
好比咱們要將二維數組 [[1,2],[3,4],[5,6]] 降維成一維數組,最簡單的作法是經過flat方法,像這樣:
let arr = [[1,2],[3,4],[5,6]].flat();//[1, 2, 3, 4, 5, 6]
經過reduce也挺簡單,咱們能夠結合concat方法,像這樣:
let arr = [[1,2],[3,4],[5,6]].reduce((accumulator, current)=>accumulator.concat(current),[]);//[1, 2, 3, 4, 5, 6]
那若是是個多維數組呢,reduce能夠這樣作:
let arr = [0,[1],[2, 3],[4, [5, 6, 7]]]; let dimensionReduction = function (arr) { return arr.reduce((accumulator, current) => { return accumulator.concat( Array.isArray(current) ? dimensionReduction(current) : current ); }, []); } dimensionReduction(arr); //[0, 1, 2, 3, 4, 5, 6, 7]
相對而言,多維數組降維flat會更簡單,固然flat存在兼容問題:
let arr = [0,[1],[2, 3],[4, [5, 6, 7]]].flat(Infinity);// [0, 1, 2, 3, 4, 5, 6, 7]
肆 ❀ 使用注意
在使用reduce方法有一點須要注意,如有初始值但數組爲空,或無初始值但數組只有一項時,reduce方法都不會執行。
[].reduce(() => console.log(1), 1); //不會執行 [1].reduce(() => console.log(1)); //不執行
若數組爲空且沒有初始值,reduce方法報錯。
[].reduce(() => console.log(1)); //報錯
因此若是沒有初始值,你至少得保證數組有2項才能執行;若是給了初始值,你至少得保證數組有一項才能執行。
[1, 2].reduce(() => console.log(1)); //1 [1].reduce(() => console.log(1), 1); //1
伍 ❀ 總
經過文本,咱們知道了reduce是一個進行累積操做的方法,當咱們提供初始值時,循環從0開始,若是不提供,則循環從索引1開始。
咱們知道了reduce還有那麼點傲嬌,若是數組爲空且不提供初始值時reduce會報錯,若是想reduce執行,你的數組最低標準應該有一項,同時提供默認值(或數組有兩項無初始值)。
那麼到這裏,關於reduce方法參數與基本用法就所有介紹完畢了。