日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Array.prototype.reduce 的理解与实现

發布時間:2023/12/9 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

總結

以上是生活随笔為你收集整理的Array.prototype.reduce 的理解与实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。