<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前一篇 你真的瞭解Array.reduce嗎? 講解了 reduce 基礎使用方法和場景的運用場景。本篇來分析一下 reduce
函數本身的實現原理。
實現 reduce 其實挺簡單的,因為它本身的執行原理也不難,就是把陣列進行遍歷,然後組成合適的引數傳遞給回撥函數,只要思路對了,去嘗試幾次,那麼就理解了 reduce 。
最具有代表性的工具庫當然是 lodash,因此本篇文章的主要內容會講解 reduce 的基本實現,以及lodash 中是怎麼來實現的,做了什麼處理。
實現思路:
function reduce(array, reducer, initialValue = null) { let value = initialValue === null ? array[0] : initialValue; // 思路1 let startIndex = initialValue === null ? 1 : 0; // 思路1 for(let i = startIndex; i < array.length; i++) { // 思路 2 const item = array[i] const res = reducer(value, item, i) // 思路3 value = res; // 思路4 } return value; // 思路5 }
測試一下:
console.log(reduce([1,2,3], (a, b) => (a + b), 0)) // 6 console.log(reduce([1,2,3], (a, b) => (a + b))) // 6
看起來是不是挺簡單的,程式碼其實還可以更簡潔一點:
function reduce(array, reducer, value = null) { value = value === null ? array[0] : value; for(let i = null ? 1 : 0; i < array.length; i++) { value = reducer(value, array[i], i); } return value; }
lodash中 的 reduce 不僅可以對陣列生效,也可以對普通 object 、類陣列物件生效。
不過也針對陣列其實單獨實現了一個 arrayReduce
函數,不過沒有對外。
來看一下 reduce
和 arrayReduce
原始碼
function reduce(collection, iteratee, accumulator) { const func = Array.isArray(collection) ? arrayReduce : baseReduce const initAccum = arguments.length < 3 return func(collection, iteratee, accumulator, initAccum, baseEach) } function arrayReduce(array, iteratee, accumulator, initAccum) { let index = -1 const length = array == null ? 0 : array.length if (initAccum && length) { accumulator = array[++index] } while (++index < length) { accumulator = iteratee(accumulator, array[index], index, array) } return accumulator }
看得懂嗎?不理解的話看下面一份程式碼,我把非陣列型別的程式碼去掉,再調一下變數命名和新增註釋:
function reduce(array, reducer, value) { const noInitialValue = arguments.length < 3 // 用引數的數量來判斷是否有初始值 let index = -1 // 遍歷索引 - 1,因為下面 while 迴圈前先加了 1 const length = array == null ? 0 : array.length // 判斷陣列是否存在和快取陣列長度 // 這個if 語句中做了我上面思路1中初始值的問題和遍歷次數的問題 if (noInitialValue && length) { // && length 判斷了陣列是否為空 value = array[++index] // 沒有有初始值,則取陣列中第一為,注意 index 變成了0,下面 while 迴圈前會先加 1,因此迴圈次數會少一次。 } while (++index < length) { value = reducer(value, array[index], index, array) } return value }
可以看出其實大部分邏輯還是和前面的簡單實現差不多,不過考慮更全一些,有值得借鑑的地方:
下面我們再看一下,去除陣列相關的程式碼來看看針對其他物件型別怎麼處理的。
function reduce(collection, iteratee, accumulator) { const func = baseReduce; const initAccum = arguments.length < 3 return func(collection, iteratee, accumulator, initAccum, baseEach) }
其他型別的都會教給 baseReduce
函數去處理。
// baseReduce function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { // 使用外部傳遞進來的遍歷方法進行遍歷物件,然後傳遞了一個 callback 給 eachFunc eachFunc(collection, (value, index, collection) => { // 初始值設定, accumulator = initAccum ? (initAccum = false, value) : iteratee(accumulator, value, index, collection) }) return accumulator }
使用外部傳遞進來的遍歷方法進行遍歷物件,然後傳遞了一個 callback 給 eachFunc,來執行 iteratee (也就是前面說的reducer),callback 內部的程式碼就和前面 for 迴圈或者 while 迴圈的程式碼類似的,就是組合引數傳遞給 reducer 進行執行,不過直接看可能有點不好理解中,瞭解了原理再來看應該可以理解,注意事項:
eachFunc
用的是 reduce
中傳遞進來的 baseEach
,內部主要就是對物件屬性進行遍歷的操作,然後把屬性值和索引以及物件本身傳遞給 callback,稍微需要注意的就是可能遇到類陣列的物件,為了保證順序,使用類陣列放入索引進行遍歷,而其他物件並不能保證屬性的傳遞順序,可以再看一下baseEach實現的程式碼:
function baseEach(collection, iteratee) { if (collection == null) { return collection } // 不是類陣列則使用 baseForOwn 處理 if (!isArrayLike(collection)) { return baseForOwn(collection, iteratee) } const length = collection.length const iterable = Object(collection) // 使用arguments測試了一下,好像沒啥作用 let index = -1 // 遍歷類陣列 while (++index < length) { if (iteratee(iterable[index], index, iterable) === false) { break } } return collection }
不是 isArrayLike
的物件遍歷與本篇文章的內容沒有啥關係了,因此就不深入了。
最近一直在學函數語言程式設計,而 reduce 可以很好的契合函數語言程式設計中的函陣列合思想,因此最近幾篇文章中都涉及到它,就想一次性把它給寫透徹,希望對讀者又一些幫助。
以上就是reduce探索lodash.reduce實現原理解析的詳細內容,更多關於reduce lodash.reduce實現的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45