Array.prototype.reduce 的理解與實現

Array.prototype.reduce 是 JavaScript 中比較實用的一個函數,但是很多人都沒有使用過它,因為 reduce 能做的事情其實 forEach 或者 map 函數也能做,而且比 reduce 好理解。但是 reduce 函數還是值得去了解的。

reduce 函數可以對一個數組進行遍歷,然后返回一個累計值,它使用起來比較靈活,下面了解一下它的用法。

reduce 接受兩個參數,第二個參數可選:

@param {Function} callback 迭代數組時,求累計值的回調函數
@param {Any} initVal 初始值,可選

其中,callback 函數可以接受四個參數:

@param {Any} acc 累計值
@param {Any} val 當前遍歷的值
@param {Number} key 當前遍歷值的索引
@param {Array} arr 當前遍歷的數組

callback 接受這四個參數,經過處理后返回新的累計值,而這個累計值會作為新的 acc 傳遞給下一個 callback 處理。直到處理完所有的數組項。得到一個最終的累計值。

reduce 接受的第二個參數是一個初始值,它是可選的。如果我們傳遞了初始值,那么它會作為 acc 傳遞給第一個 callback,此時 callback 的第二個參數 val 是數組的第一項;如果我們沒有傳遞初始值給 reduce,那么數組的第一項會作為累計值傳遞給 callback,數組的第二項會作為當前項傳遞給 callback。

示例:

對數組求和:

let arr = [1, 2, 3];
let res = arr.reduce((acc, v) => acc + v);
console.log(res); // 6

如果我們傳遞一個初始值:

let arr = [1, 2, 3];
let res = arr.reduce((acc, v) => acc + v, 94);
console.log(res); // 100

利用 reduce 求和比 forEach 更加簡單,代碼也更加優雅,只需要清楚 callback 接受哪些參數,代表什么含義就可以了。

我們還可以利用 reduce 做一些其他的事情,比如對數組去重:

let arr = [1, 1, 1, 2, 3, 3, 4, 3, 2, 4];
let res = arr.reduce((acc, v) => {if (acc.indexOf(v) < 0) acc.push(v);return acc;
}, []);
console.log(res); // [1, 2, 3, 4]

統計數組中每一項出現的次數:

let arr = ['Jerry', 'Tom', 'Jerry', 'Cat', 'Mouse', 'Mouse'];
let res = arr.reduce((acc, v) => {if (acc[v] === void 0) acc[v] = 1;else acc[v]++;return acc;
}, {});
console.log(res); // {Jerry: 2, Tom: 1, Cat: 1, Mouse: 2}

將二維數組展開成一維數組:

let arr = [[1, 2, 3], 3, 4, [3, 5]];
let res = arr.reduce((acc, v) => {if (v instanceof Array) {return [...acc, ...v];} else {return [...acc, v];}
});
console.log(res); // [1, 2, 3, 3, 4, 3, 5]

由此可以看出,reduce 函數還是很實用的,但是 reduce 函數兼容性不是特別好,只支持到 IE 9,如果要在 IE 8 及以下使用的話就不行了,所以我們可以自己實現一下,還可以對其做一下擴展,使其能夠遍歷對象。

首先可以實現一個最基礎的 each 函數,作為我們 reduce 的基礎:

/*** 遍歷對象或數組,對操作對象的屬性或元素做處理* @param {Object|Array} param 要遍歷的對象或數組* @param {Function} callback 回調函數*/
function each(param, callback) {// ...省略參數校驗if (param instanceof Array) {for (var i = 0; i < param.length; i++) {callback(param[i], i, param);}} else if (Object.prototype.toString.call(param) === '[object Object]') {for (var val in param) {callback(param[val], val, param);}} else {throw new TypeError('each 參數錯誤!');}
}

可以看出 each 可以遍歷對象或數組,回調函數接受三個參數:

@param {Any} v 當前遍歷項
@param {String|Number} k 當前遍歷的索引或鍵
@param {Object|Array} o 當前遍歷的對象或者數組

有了這個基礎函數,我們可以開始實現我們的 reduce 函數了:

/*** 迭代數組、類數組對象或對象,返回一個累計值* @param {Object|Array} param 要迭代的數組、類數組對象或對象* @param {Function} callback 對每一項進行操作的回調函數,接收四個參數:acc 累加值、v 當前項、k 當前索引、o 當前迭代對象* @param {Any} initVal 傳入的初始值*/
function reduce(param, callback, initVal) {var hasInitVal = initVal !== void 0;var acc = hasInitVal ? initVal : param[0];each(hasInitVal ? param : Array.prototype.slice.call(param, 1), function(v, k, o) {acc = callback(acc, v, k, o);});return acc;
}

可以看到,我們的 reduce 函數就是在 each 上面封裝了一層。根據是否傳遞了初始值 initVal 來決定遍歷的起始項。每次遍歷都接受 callback 返回的 acc 值,然后在 reduce 的最后返回 acc 累計值就可以啦!

當然,這部分代碼有一個很嚴重的 bug,導致了我們的 polyfill 毫無意義,那就是遍歷對象時的 for...in。這個語法和在 IE <= 9 環境下存在 bug,會無法獲得對象的屬性值,這就導致我們所實現的 reduce 無法在 IE 9 以下遍歷對象,但是遍歷數組還是可以的。對于 for...in 的這個 bug,可以參考 underscore 是怎么實現的,這里暫時不研究了~

轉載于:https://www.cnblogs.com/DM428/p/10126885.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276646.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276646.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276646.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PS摳圖方法[photoshop中文教程]

PS摳圖方法 一、魔術棒法——最直觀的方法   適用范圍&#xff1a;圖像和背景色色差明顯&#xff0c;背景色單一&#xff0c;圖像邊界清晰。   方法意圖&#xff1a;通過刪除背景色來獲取圖像。   方法缺陷&#xff1a;對散亂的毛發沒有用。   使用方法&#xff1a…

我的核心技術都是從哪里學到的?如何提高成長的?分享給大家。

1997年&#xff0c;我在讀黑龍江大學讀大二時&#xff0c;我認識了一個內蒙古大學計算機專業畢業的一個高材生&#xff0c;那時我那朋友引導了我很多&#xff0c;他那時候在我們家那邊開一個IT公司&#xff0c;他知道如何靠IT技術賺錢&#xff0c;如何靠程序等賺錢&#xff0c;…

python線性回歸算法簡介_Python實現的簡單線性回歸算法實例分析

本文實例講述了Python實現的簡單線性回歸算法。分享給大家供大家參考&#xff0c;具體如下&#xff1a; 用python實現R的線性模型(lm)中一元線性回歸的簡單方法&#xff0c;使用R的women示例數據&#xff0c;R的運行結果&#xff1a; > summary(fit) Call: lm(formula weig…

Object/Relation Mapping 對象關系映射

對象-關系映射&#xff08;Object/Relation Mapping&#xff0c;簡稱ORM&#xff09;&#xff0c;是隨著面向對象的軟件開發方法發展而產生的。面向對象的開發方法是當今企業級應用開發環境中的主流開發方法&#xff0c;關系數據庫是企業級應用環境中永久存放數據的主流數據存儲…

FastReport使用方法(C/S版)

前言 這兩天群里一直有群友問一些關于FastReport的問題&#xff0c;結合他們的問題&#xff0c;在這里做一個整理&#xff0c;有不明白的可以加 FastReport 交流群 群 號&#xff1a;554714044 工具 VS2017 FastReport 開始 1.新建項目&#xff0c;添加三個按鈕。預覽、設計、…

如何設置Linux時區為東八區

當我們購買美國VPS或服務器的時候&#xff0c;默認情況下是美國時間。對于我們定時執行某些任務會帶來麻煩&#xff0c;所以需要設置時區為東八區。登錄SSH后&#xff0c;執行tzselect命令。我們這里選擇亞洲5.這里選擇china 9。一般選東八區&#xff08;北京&#xff0c;廣東&…

python刪除兩個excel表中的相同元素_python篩選出兩個文件中重復行的方法

查找A文件中&#xff0c;與B文件中內容不重復的內容#!usr/bin/python import sys import os字符串查找函數&#xff0c;使用二分查找法在列表中進行查詢def binarySearch(value, lines): right len(lines) - 1 left 0 a value.strip() while left < right: middle int((…

求解:nhibernate2.0操作oralce提交事務時報錯

代碼如下: Configuration config new Configuration(); config.AddAssembly("TestCleanSnow"); ISessionFactory factory config.BuildSessionFactory(); ISession session f…

python畫楓葉_python-文件的操作

一、異常 程序在運行的過程中&#xff0c;不可避免出現一些錯誤&#xff0c;這些錯誤成為異常 異常以后的代碼都不會被執行 try 語句 代碼塊&#xff08;可能出現錯誤的語句&#xff09; except 異常類型 as 異常名: 代碼塊(出錯以后執行的語句&#xff09; except 異常類型 as…

記2018年技術人一次短暫的創業

背景 2018年8月底&#xff0c;我全職加入了一家創業公司&#xff0c;具體做什么我暫時先不說吧&#xff0c;我是產品和技術負責人&#xff0c;自己出資了50w&#xff0c;大股東&#xff08;下面簡稱T)也就是ceo是早期阿里出身的中供銷售&#xff0c;從2017年11月開始成立此公司…

如何在Apache環境下配置Rewrite規則

原文鏈接&#xff1a;http://faq.comsenz.com/viewnews-12 URL 靜態化是一個利于搜索引擎的設置&#xff0c;通過 URL 靜態化&#xff0c;達到原來是動態的 PHP 頁面轉換為靜態化的 HTML 頁面&#xff0c;當然&#xff0c;這里的靜態化是一種假靜態&#xff0c;目的只是提高搜…

情 人 節 快 樂

我不善于用詞匯修飾我的句子&#xff0c; 我不善于用表情表達我的心情&#xff0c; 我不善于解讀你那黯然的情緒&#xff0c; 我不善于去響應你小小的呼應&#xff0c; 雖然&#xff0c;你了解我&#xff0c; 你寬容于我&#xff0c; 你聽我訴說&#xff0c; 你陪伴著我…

Windows 10系統安裝JDK1.8與配置環境

第一步&#xff1a;下載JDK1.8 地址:https://www.oracle.com/index.html 第二步&#xff1a; 安裝分兩次&#xff0c;第一次是安裝 jdk &#xff0c;第二次是安裝 jre 。安裝jdk默認的安裝地址為C盤&#xff0c;安裝目錄 \java 之前的目錄修改成你想放的目錄&#xff1b;安裝jr…

python3函數調用時間_Python3 time clock()方法

Python3 time clock()方法 描述 Python 3.8 已移除 clock() 方法 可以使用 time.perf_counter() 或 time.process_time() 方法替代。 Python time clock() 函數以浮點數計算的秒數返回當前的CPU時間。用來衡量不同程序的耗時&#xff0c;比time.time()更有用。 這個需要注意&am…

給apache安裝mod_rewrite模塊

給apache安裝mod_rewrite模塊 原文鏈接&#xff1a;http://opkeep.com/system/linux/apache_mod_rewrite.html 只是用來做參考,相關情況可跟據自己的需求進行修改 如果你的服務器apache還沒有安裝&#xff0c;那很簡單&#xff0c;在編譯apache時將mod_rewrite模塊編譯進去就可…

Oracle9i 問題匯總--不斷更新中

1.創建數據表時&#xff0c;用戶表空間不足&#xff0c;解決方法 ALTER USER USERNAME QUOTA UNLIMITED ON USERS 2.避免在On條件上使用字符串串連 或者 函數。 如&#xff1a;ON 0||S.LIST_NOMS.EXTEND_FIELD 以上SQL語句會造成查詢嚴重變慢&#xff0c;如果非要使用請使用&…

武漢區塊鏈軟件公司:區塊鏈游戲和普通的游戲有什么區別?

武漢區塊鏈軟件公司:區塊鏈游戲和普通的游戲有什么區別&#xff1f;最近&#xff0c;各公鏈DAPP的開發呈迸發之勢&#xff0c;其中有虛擬財物使用的游戲就天然有上鏈的優勢。區塊鏈游戲也被認為是繼金融范疇之后第二個取得區塊鏈落地使用場景范疇。為什么游戲類DAPP能得到快速展…

git安裝與配置_git 安裝及基本配置

git 基本上來說是開發者必備工具了&#xff0c;在服務器里沒有 git 實在不太能說得過去。何況&#xff0c;沒有 git 的話&#xff0c;面向github編程 從何說起&#xff0c;如同一個程序員斷了左膀右臂。你對流程熟悉后&#xff0c;只需要一分鐘便可以操作完成原文地址: 服務器 …

Apache偽靜態學習

原文鏈接&#xff1a;http://www.benben.cc/blog/?p305 Apache中有著這樣一個模塊&#xff0c;它默默無聞&#xff0c;卻是URL操作的瑞士軍刀&#xff01;有人這樣評價它&#xff1a;“盡管它的例子和文檔數量可以以噸來計算&#xff0c;但它仍然是巫術&#xff0c;該死的巫術…

不同的容器里實現 RadioButton的單選

請教一個各位牛人一個問題&#xff0c;如圖&#xff1a; &#xff08;問題解決&#xff0c;見后面的解決方案~~&#xff09; 怎么在不同的winform容器(GroupBox)里實現 RadioButton &#xff08;如圖中兩個“詳細照會”&#xff09;的單選&#xff0c;請各位牛人給出實現的思…