欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

reduce探索lodash.reduce實(shí)現(xiàn)原理解析

 更新時(shí)間:2023年02月27日 08:35:01   作者:Hutao  
這篇文章主要為大家介紹了reduce探索lodash.reduce實(shí)現(xiàn)原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

前一篇 你真的了解Array.reduce嗎? 講解了 reduce 基礎(chǔ)使用方法和場(chǎng)景的運(yùn)用場(chǎng)景。本篇來(lái)分析一下 reduce 函數(shù)本身的實(shí)現(xiàn)原理。

實(shí)現(xiàn) reduce 其實(shí)挺簡(jiǎn)單的,因?yàn)樗旧淼倪\(yùn)行原理也不難,就是把數(shù)組進(jìn)行遍歷,然后組成合適的參數(shù)傳遞給回調(diào)函數(shù),只要思路對(duì)了,去嘗試幾次,那么就理解了 reduce 。

最具有代表性的工具庫(kù)當(dāng)然是 lodash,因此本篇文章的主要內(nèi)容會(huì)講解 reduce 的基本實(shí)現(xiàn),以及l(fā)odash 中是怎么來(lái)實(shí)現(xiàn)的,做了什么處理。

基本實(shí)現(xiàn)

實(shí)現(xiàn)思路:

  • 判斷是否有初始值,因?yàn)橛谐跏贾岛蜎](méi)有初始值對(duì)回調(diào)函數(shù)(reducer)執(zhí)行的次數(shù)是有影響的。
  • 遍歷數(shù)組
  • 組合參數(shù)傳遞給 reducer 進(jìn)行執(zhí)行
  • 獲取到第三步返回值的時(shí)候,要把返回值存儲(chǔ)起來(lái),在下一次便利的時(shí)候作為reducer第一個(gè)參數(shù)來(lái)替換初始值。
  • 返回最終計(jì)算的value值
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
}

測(cè)試一下:

console.log(reduce([1,2,3], (a, b) => (a + b), 0)) // 6
console.log(reduce([1,2,3], (a, b) => (a + b))) // 6

看起來(lái)是不是挺簡(jiǎn)單的,代碼其實(shí)還可以更簡(jiǎn)潔一點(diǎn):

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 實(shí)現(xiàn)有何不同?

lodash中 的 reduce 不僅可以對(duì)數(shù)組生效,也可以對(duì)普通 object 、類數(shù)組對(duì)象生效。

不過(guò)也針對(duì)數(shù)組其實(shí)單獨(dú)實(shí)現(xiàn)了一個(gè) arrayReduce 函數(shù),不過(guò)沒(méi)有對(duì)外。

來(lái)看一下 reducearrayReduce 源碼

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
}

看得懂嗎?不理解的話看下面一份代碼,我把非數(shù)組類型的代碼去掉,再調(diào)一下變量命名和新增注釋:

function reduce(array, reducer, value) {
  const noInitialValue = arguments.length < 3 // 用參數(shù)的數(shù)量來(lái)判斷是否有初始值
  
  let index = -1 // 遍歷索引 - 1,因?yàn)橄旅?while 循環(huán)前先加了 1
  const length = array == null ? 0 : array.length // 判斷數(shù)組是否存在和緩存數(shù)組長(zhǎng)度
  // 這個(gè)if 語(yǔ)句中做了我上面思路1中初始值的問(wèn)題和遍歷次數(shù)的問(wèn)題
  if (noInitialValue && length) { // && length 判斷了數(shù)組是否為空
    value = array[++index] // 沒(méi)有有初始值,則取數(shù)組中第一為,注意 index 變成了0,下面 while 循環(huán)前會(huì)先加 1,因此循環(huán)次數(shù)會(huì)少一次。
  }
  while (++index < length) {
    value = reducer(value, array[index], index, array)
  }
  return value
}

可以看出其實(shí)大部分邏輯還是和前面的簡(jiǎn)單實(shí)現(xiàn)差不多,不過(guò)考慮更全一些,有值得借鑒的地方:

  • 參數(shù)判斷邏輯更有力,不管外界傳遞了第三個(gè)參數(shù)是啥,都說(shuō)明有初始值
  • 考慮了數(shù)組不存在或者為空的情況

下面我們?cè)倏匆幌?,去除?shù)組相關(guān)的代碼來(lái)看看針對(duì)其他對(duì)象類型怎么處理的。

function reduce(collection, iteratee, accumulator) {
  const func = baseReduce;
  const initAccum = arguments.length < 3
  return func(collection, iteratee, accumulator, initAccum, baseEach)
}

其他類型的都會(huì)教給 baseReduce 函數(shù)去處理。

// baseReduce
function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
  // 使用外部傳遞進(jìn)來(lái)的遍歷方法進(jìn)行遍歷對(duì)象,然后傳遞了一個(gè) callback 給 eachFunc
  eachFunc(collection, (value, index, collection) => {
    // 初始值設(shè)置,
    accumulator = initAccum
      ? (initAccum = false, value)
      : iteratee(accumulator, value, index, collection)
  })
  return accumulator
}

使用外部傳遞進(jìn)來(lái)的遍歷方法進(jìn)行遍歷對(duì)象,然后傳遞了一個(gè) callback 給 eachFunc,來(lái)執(zhí)行 iteratee (也就是前面說(shuō)的reducer),callback 內(nèi)部的代碼就和前面 for 循環(huán)或者 while 循環(huán)的代碼類似的,就是組合參數(shù)傳遞給 reducer 進(jìn)行執(zhí)行,不過(guò)直接看可能有點(diǎn)不好理解中,了解了原理再來(lái)看應(yīng)該可以理解,注意事項(xiàng):

  • initAccum 為 false 時(shí),說(shuō)明有初始值,直接執(zhí)行 iteratee。
  • initAccum 為 true,說(shuō)明沒(méi)有初始值,需要添加初始值,因此第一次循環(huán)就是賦值給初始值,然后把 initAccum 設(shè)置為false,沒(méi)有進(jìn)行執(zhí)行 iteratee,比沒(méi)有初始值少一次執(zhí)行,符合邏輯。

eachFunc 用的是 reduce 中傳遞進(jìn)來(lái)的 baseEach,內(nèi)部主要就是對(duì)對(duì)象屬性進(jìn)行遍歷的操作,然后把屬性值和索引以及對(duì)象本身傳遞給 callback,稍微需要注意的就是可能遇到類數(shù)組的對(duì)象,為了保證順序,使用類數(shù)組放入索引進(jìn)行遍歷,而其他對(duì)象并不能保證屬性的傳遞順序,可以再看一下baseEach實(shí)現(xiàn)的代碼:

function baseEach(collection, iteratee) {
  if (collection == null) {
    return collection
  }
  // 不是類數(shù)組則使用 baseForOwn 處理
  if (!isArrayLike(collection)) {
    return baseForOwn(collection, iteratee)
  }
  const length = collection.length
  const iterable = Object(collection) // 使用arguments測(cè)試了一下,好像沒(méi)啥作用
  let index = -1

  // 遍歷類數(shù)組
  while (++index < length) {
    if (iteratee(iterable[index], index, iterable) === false) {
      break
    }
  }
  return collection
}

不是 isArrayLike 的對(duì)象遍歷與本篇文章的內(nèi)容沒(méi)有啥關(guān)系了,因此就不深入了。

總結(jié)

最近一直在學(xué)函數(shù)式編程,而 reduce 可以很好的契合函數(shù)式編程中的函數(shù)組合思想,因此最近幾篇文章中都涉及到它,就想一次性把它給寫透徹,希望對(duì)讀者又一些幫助。

以上就是reduce探索lodash.reduce實(shí)現(xiàn)原理解析的詳細(xì)內(nèi)容,更多關(guān)于reduce lodash.reduce實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 前端JavaScript算法找出只出現(xiàn)一次的數(shù)字

    前端JavaScript算法找出只出現(xiàn)一次的數(shù)字

    這篇文章主要為大家介紹了前端JavaScript算法找出只出現(xiàn)一次的數(shù)字的算法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 微信小程序 跳轉(zhuǎn)傳遞數(shù)據(jù)的實(shí)例

    微信小程序 跳轉(zhuǎn)傳遞數(shù)據(jù)的實(shí)例

    這篇文章主要介紹了微信小程序 跳轉(zhuǎn)傳遞數(shù)據(jù)的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • JavaScript?history?對(duì)象詳解

    JavaScript?history?對(duì)象詳解

    這篇文章主要介紹了JavaScript?history?對(duì)象詳解,history?對(duì)象表示當(dāng)前窗口首次使用以來(lái)用戶的導(dǎo)航歷史記錄。因?yàn)?history?是?window?的屬性,所以每個(gè)?window?都有自己的?history?對(duì)象,更多詳細(xì)內(nèi)容請(qǐng)參考下面文章內(nèi)容
    2021-11-11
  • JavaScript執(zhí)行機(jī)制詳細(xì)介紹

    JavaScript執(zhí)行機(jī)制詳細(xì)介紹

    這篇文章主要介紹了JavaScript執(zhí)行機(jī)制,想要搞懂JavaScript執(zhí)行機(jī)制,便與進(jìn)程與線程的概念脫不了干系,下面我們就來(lái)看看這JavaScript執(zhí)行機(jī)制的具體介紹吧,需要的朋友可以參考一下
    2021-12-12
  • Javascript基礎(chǔ)知識(shí)中關(guān)于內(nèi)置對(duì)象的知識(shí)

    Javascript基礎(chǔ)知識(shí)中關(guān)于內(nèi)置對(duì)象的知識(shí)

    這篇文章主要介紹了Javascript基礎(chǔ)知識(shí)中關(guān)于內(nèi)置對(duì)象的相關(guān)知識(shí)的相關(guān)資料,需要的朋友可以參考下面小編薇大家?guī)?lái)的精彩文章
    2021-09-09
  • 精確到按鈕級(jí)別前端權(quán)限管理實(shí)現(xiàn)方案

    精確到按鈕級(jí)別前端權(quán)限管理實(shí)現(xiàn)方案

    這篇文章主要為大家介紹了精確到按鈕級(jí)別前端權(quán)限管理實(shí)現(xiàn)方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • ChatGPT前端編程秀之別拿編程語(yǔ)言不當(dāng)語(yǔ)言

    ChatGPT前端編程秀之別拿編程語(yǔ)言不當(dāng)語(yǔ)言

    這篇文章主要為大家介紹了ChatGPT前端編程秀之教你別拿編程語(yǔ)言不當(dāng)語(yǔ)言,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 解決React中的re-render問(wèn)題

    解決React中的re-render問(wèn)題

    這篇文章主要介紹了解決React中的re-render問(wèn)題,相信很多人都遇到過(guò)。接下來(lái)給大家具體講講這個(gè)問(wèn)題,需要的朋友可以參考y一下,洗碗給對(duì)你有所幫助
    2022-01-01
  • Lambda表達(dá)式原理及示例

    Lambda表達(dá)式原理及示例

    這篇文章主要介紹了Java8中的新特性Lambda表達(dá)式,文中的示例可以幫助大家快速了解該特性,感興趣的小伙伴可以一起學(xué)習(xí)
    2021-08-08
  • 微信小程序 video組件詳解

    微信小程序 video組件詳解

    這篇文章主要介紹了微信小程序 video組件詳解的相關(guān)資料,需要的朋友可以參考下
    2016-10-10

最新評(píng)論