<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官直呼內(nèi)行!如何實現(xiàn)一個比較完美的reduce函數(shù)?

          共 7104字,需瀏覽 15分鐘

           ·

          2022-09-10 15:40

          大廠技術 ?? 高級前端 ?? Node進階

          點擊上方? 程序員成長指北 ,關注公眾號

          回復 1 ,加入高級Node交流群

          基本用法

          reduce函數(shù)是js原生提供的用于處理數(shù)組結構的函數(shù)。

          先來看一下MDN中的介紹:

          reduce()?方法對數(shù)組中的每個元素按序執(zhí)行一個由用戶提供的?reducer?函數(shù),每一次運行?reducer?會將先前元素的計算結果作為參數(shù)傳入,最后將其結果匯總為單個返回值。

          參數(shù)

          1. callbackFn?一個?reducer?函數(shù),包含四個參數(shù):
          • previousValue:上一次調(diào)用?callbackFn時的返回值。在第一次調(diào)用時,若指定了初始值?initialValue,其值則為?initialValue,否則為數(shù)組索引為 0 的元素?array[0]。
          • currentValue:數(shù)組中正在處理的元素。在第一次調(diào)用時,若指定了初始值?initialValue,其值則為數(shù)組索引為 0 的元素?array[0],否則為?array[1]。
          • currentIndex:數(shù)組中正在處理的元素的索引。若指定了初始值?initialValue,則起始索引號為 0,否則從索引 1 起始。
          • array:用于遍歷的數(shù)組。
          1. initialValue?可選 作為第一次調(diào)用?callback?函數(shù)時參數(shù)?previousValue?的值。若指定了初始值?initialValue,則?currentValue?則將使用數(shù)組第一個元素;否則?previousValue?將使用數(shù)組第一個元素,而?currentValue?將使用數(shù)組第二個元素。

          reduce函數(shù)功能是非常強大的適用于非常多的場景:

          比如使用reduce函數(shù)實現(xiàn)累加:

              ??let?total?=?[?0,?1,?2,?3?].reduce(
          ????(?previousValue,?currentValue?)?=>?previousValue?+?currentValue,
          ????0
          ??)
          ??//?6

          生成新數(shù)組:

              ??let?total?=?[?0,?1,?2,?3?].reduce(
          ????function?(pre,?cur)?{
          ??????pre.push(cur?+?1)
          ??????return?pre
          ????},
          ????[]
          ??)
          ??//?[1,?2,?3,?4]

          等等.....

          那么問題來了,如何手寫實現(xiàn)一個reduce函數(shù)呢?

          實現(xiàn)基礎版本

          根據(jù)文檔可知,reduce函數(shù)接受一個運行函數(shù)和一個初始的默認值

              ???/**
          ????*
          ????*?@param?{Array}?data?原始數(shù)組
          ????*?@param?{Function}?iteratee?運行函數(shù)
          ????*?@param?{Any}?memo?初始值
          ????*?@returns?{boolean}?True?if?value?is?an?FormData,?otherwise?false
          ????*/

          ??function?myReduce(data,?iteratee,?memo)?{
          ??????//?...
          ??}

          接下來實現(xiàn)基本功能

          reduce函數(shù)的重點就是要將結果再次傳入執(zhí)行函數(shù)中進行處理

              ??function?myReduce(data,?iteratee,?memo)?{
          ???for(let?i?=?0;?i?<?data.length;?i++)?{
          ????memo?=?iteratee(memo,?data[i],?i,?data)
          ???}
          ???return?memo
          ??}

          需求一:增加this綁定

          其實reduce函數(shù)可以指定自定義對象綁定this

          在這里可以使用call對函數(shù)進行重新綁定

              ??function?myReduce(data,?iteratee,?memo,?context)?{
          ???//?重置iteratee函數(shù)的this指向
          ???iteratee?=?bind(iteratee,?context)
          ??
          ???for(let?i?=?0;?i?<?data.length;?i++)?{
          ????memo?=?iteratee(memo,?data[i],?i,?data)
          ???}
          ???return?memo
          ??}
          ??
          ??//?綁定函數(shù)?使用call進行綁定
          ??function?bind(fn,?context)?{
          ????//?返回一個匿名函數(shù),執(zhí)行時重置this指向
          ????return?function(memo,?value,?index,?collection)?{
          ??????return?fn.call(context,?memo,?value,?index,?collection);
          ????};
          ??}
          ??

          需求二:增加對第二個參數(shù)默認值的支持

          reduce函數(shù)的第三個參數(shù)也是可選值,如果沒有傳遞第三個參數(shù),那么直接使用傳入數(shù)據(jù)的第一個位置初始化

              ??function?myReduce(data,?iteratee,?memo,?context)?{
          ???//?重置iteratee函數(shù)的this指向
          ???iteratee?=?bind(iteratee,?context)
          ???//?判斷是否傳遞了第三個參數(shù)
          ???let?initial??=?arguments.length?>=?3;?//?新增
          ???//?初始的遍歷下標
          ???let?index?=?0?//?新增
          ??
          ???if(!initial)?{?//?新增
          ????//?如果用戶沒有傳入默認值,那么就取數(shù)據(jù)的第一項作為默認值
          ????memo?=?data[index]?//?新增
          ????//?所以遍歷就要從第二項開始
          ????index?+=?1?//?新增
          ???}
          ??
          ???for(let?i?=?index;?i?<?data.length;?i++)?{?//?修改
          ????memo?=?iteratee(memo,?data[i],?i,?data)
          ???}
          ???return?memo
          ??}
          ??
          ??//?綁定函數(shù)?使用call進行綁定
          ??function?bind(fn,?context)?{
          ????return?function(memo,?value,?index,?collection)?{
          ??????return?fn.call(context,?memo,?value,?index,?collection);
          ????};
          ??}
          ??

          需求三:支持對象

          js原生的reduce函數(shù)是不支持對象這種數(shù)據(jù)結構的,那么如何完善我們的reduce函數(shù)呢?

          其實只需要取出對象中所有的key,然后遍歷key就可以了

              ?function?myReduce(data,?iteratee,?memo,?context)?{
          ?
          ???iteratee?=?bind(iteratee,?context)
          ???//?取出所有的key值
          ???let?_keys?=?!Array.isArray(data)?&&?Object.keys(data)?//?新增
          ???//?長度賦值
          ???let?len?=?(_keys?||?data).length?//?新增
          ?
          ???let?initial??=?arguments.length?>=?3;
          ???let?index?=?0
          ??
          ???if(!initial)?{
          ????//?如果沒有設置默認值初始值,那么取第一個值的操作也要區(qū)分對象/數(shù)組
          ????memo?=?data[?_keys???_keys[index]?:?index]?//?修改
          ????index?+=?1
          ???}
          ??
          ???for(let?i?=?index;?i?<?len;?i++)?{
          ????//?取key值
          ????let?currentKey?=?_keys???_keys[i]?:?i?//?新增
          ????memo?=?iteratee(memo,?data[currentKey],?currentKey,?data)?//?修改
          ???}
          ???return?memo
          ??}
          ??
          ??function?bind(fn,?context)?{
          ????return?function(memo,?value,?index,?collection)?{
          ??????return?fn.call(context,?memo,?value,?index,?collection);
          ????};
          ??}
          ??

          需求四:reduceRight

          其實以上的內(nèi)容已經(jīng)是一個比較完整的reduce函數(shù)了,最后一個擴展內(nèi)容是reduceRight函數(shù),其實reduceRight函數(shù)的功能也很簡單,就是在遍歷的時候倒序進行操作,例如:

              ?let?total?=?[?0,?1,?2,?3?].reduce(
          ????function?(pre,?cur)?{
          ??????pre.push(cur?+?1)
          ??????return?pre
          ????},
          ????[]
          ??)
          ??
          ??//?[1,?2,?3,?4]

          其實實現(xiàn)這個功能也非常簡單,只需要初始操作的值更改為最后一個元素的位置就可以了:

              //?加入一個參數(shù)dir,用于標識正序/倒序遍歷
          function?myReduce(data,?iteratee,?memo,?context,?dir)?{?//修改

          ??iteratee?=?bind(iteratee,?context)
          ??let?_keys?=?!Array.isArray(data)?&&?Object.keys(data)
          ??let?len?=?(_keys?||?data).length

          ??let?initial??=?arguments.length?>=?3;

          ??//?定義下標
          ??let?index?=?dir?>?0???0?:?len?-?1?//?修改
          ?
          ??if(!initial)?{
          ???memo?=?data[?_keys???_keys[index]?:?index]
          ???//?定義初始值
          ???index?+=?dir?//?修改
          ??}
          ??//?每次修改只需步進指定的值
          ??for(;index?>=?0?&&?index?<?len;?index?+=?dir)?{?//?修改
          ???let?currentKey?=?_keys???_keys[index]?:?index
          ???memo?=?iteratee(memo,?data[currentKey],?currentKey,?data)
          ??}
          ??return?memo
          ?}
          ?
          ?function?bind(fn,?context)?{
          ???if?(!context)?return?fn;
          ???return?function(memo,?value,?index,?collection)?{
          ?????return?fn.call(context,?memo,?value,?index,?collection);
          ???};
          ?}

          調(diào)用的時候直接傳入最后一個參數(shù)為1 / \-1即可

              ?myReduce([1,?2,?3,?4],?function(pre,?cur)?{
          ?????console.log(cur)
          ?},?[],?1)
          ?
          ?myReduce([1,?2,?3,?4],?function(pre,?cur)?{
          ?????console.log(cur)
          ?},?[],?-1)

          最后將整個函數(shù)進行重構抽離成為一個單獨的函數(shù):

              ?function?createReduce(dir)?{
          ?????function?reduce()?{
          ???//?....
          ?????}
          ?
          ?????return?function()?{
          ???return?reduce()
          ?????}
          ?}

          最后最終的代碼如下:

              ?function?createReduce(dir)?{
          ?
          ?????function?reduce(data,?fn,?memo,?initial)?{
          ?????????let?_keys?=?Array.isArray(data)?&&?Object.keys(data),
          ?????????????len?=?(_keys?||?data).length,
          ?????????????index?=?dir?>?0???0?:?len?-?1;

          ?????????if?(!initial)?{
          ?????????????memo?=?data[_keys???_keys[index]?:?index]
          ?????????????index?+=?dir
          ?????????}

          ?????????for?(;?index?>=?0?&&?index?<?len;?index?+=?dir)?{
          ?????????????let?currentKey?=?_keys???_keys[index]?:?index
          ?????????????memo?=?fn(memo,?data[currentKey],?currentKey,?data)
          ?????????}
          ?????????return?memo
          ?????}


          ?????return?function?(data,?fn,?memo,?context)?{
          ?????????let?initial?=?arguments.length?>=?3
          ?????????return?reduce(data,?bind(fn,?context),?memo,?initial)
          ?????}
          ?}

          ?function?bind(fn,?context)?{
          ?????if?(!context)?return?fn;
          ?????return?function?(memo,?value,?index,?collection)?{
          ?????????return?fn.call(context,?memo,?value,?index,?collection);
          ?????};
          ?}

          ?let?reduce?=?createReduce(1)
          ?let?reduceRight?=?createReduce(-1)

          而這種實現(xiàn)方式也是underscore.js所實現(xiàn)的reduce函數(shù)的方式。

          寫在最后??

          未來可能會更新實現(xiàn)mini-vue3javascript基礎知識系列,希望能一直堅持下去,期待多多點贊????,一起進步!????


          關于本文

          來自:pino

          https://juejin.cn/post/7113743909452251167


              Node 社群
                      



          我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學習感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關的交流、學習、共建。下方加 考拉 好友回復「Node」即可。



          如果你覺得這篇內(nèi)容對你有幫助,我想請你幫我2個小忙:

          1. 點個 「在看」 ,讓更多人也能看到這篇文章 2. 訂閱官方博客? www.inode.club? 讓我們一起成長

          點贊和在看就是最大的支持 ??

          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  伊人久久青青 | 奇米成人电影 | 操逼网站视频香蕉 | 国产日产精品一区二区三区四区 | 美女艹逼视频 |