JS reduce()方法詳解,使用reduce數組去重

 壹 ❀ 引面試

稍微有了解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方法參數與基本用法就所有介紹完畢了。

相關文章
相關標籤/搜索