<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)功修煉之lodash——chunk、zip、groupBy、invokeMap方法

          共 5473字,需瀏覽 11分鐘

           ·

          2020-11-05 20:19




          0a6801dde959002709b7c96e6dde20d0.webp

          如果覺得沒有面試題,那么lodash每一個(gè)方法就可以當(dāng)作一個(gè)題目,可以看著效果反過來實(shí)現(xiàn),以不同的方法實(shí)現(xiàn)、多種方法實(shí)現(xiàn),鞏固基礎(chǔ)。除了某些一瞬間就可以實(shí)現(xiàn)的函數(shù),下面抽取部分函數(shù)作為試煉。時(shí)代在進(jìn)步,下文所有的解法都采用es2015+



          本文實(shí)現(xiàn)方法都是看效果倒推實(shí)現(xiàn)方法,并進(jìn)行一些拓展和思考,和源碼無關(guān)。lodash這個(gè)庫(kù)的文檔更像一個(gè)題庫(kù),給出了題目讓我們刷題的

          能收獲什么

          1、修煉代碼基本功,了解常見的套路


          2、了解到一些操作的英文命名和規(guī)范


          3、積累經(jīng)驗(yàn),面對(duì)復(fù)雜邏輯問題可以迅速解決


          4、也許可以查到自己的js基礎(chǔ)知識(shí)的漏洞




          ??注意:

          • 三星難度以上的會(huì)具體拓展和講解

          • 文中使用的基本都是數(shù)組原生api以及es6+函數(shù)式編程,代碼簡(jiǎn)潔且過程清晰

          • 如果說性能當(dāng)然是命令式好,實(shí)現(xiàn)起來稍微麻煩一些而且比較枯燥無味

          • 時(shí)代在進(jìn)步,人生苦短,我選擇語(yǔ)法糖和api。面臨大數(shù)據(jù)的性能瓶頸,才是考慮命令式編程的時(shí)候



          chunk


          • 描述:?_.chunk(array, [size=0]),將數(shù)組拆分成多個(gè) size 長(zhǎng)度的塊,并組成一個(gè)新數(shù)組。如果數(shù)組無法被分割成全部等長(zhǎng)的塊,那么最后剩余的元素將組成一個(gè)塊。

          • 難度系數(shù):★★

          • 建議最長(zhǎng)用時(shí):6min

          // example
          _.chunk(['a', 'b', 'c', 'd'], 2);
          // => [['a', 'b'], ['c', 'd']]

          _.chunk(['a', 'b', 'c', 'd'], 3);
          // => [['a', 'b', 'c'], ['d']]


          參考代碼:

          // 常規(guī)方法
          function chunk(arr, size = 0) {
          let current = 0;
          let temp = [];
          return arr.reduce((acc, cur, i) => {
          if (current++ < size) {
          temp.push(cur);
          }
          if (temp.length === size || i === arr.length - 1) {
          acc.push(temp);
          current = 0;
          temp = [];
          }
          return acc;
          }, []);
          }

          // 抽象派
          function chunk(arr, size = 0) {
          let current = 0;
          let temp = [];
          return arr.reduce(
          (acc, cur, i) =>
          temp.push(...(current++ < size ? [cur] : [])) === size ||
          i === arr.length - 1
          ? [...acc, temp, ...((current = 0), (temp = []), [])]
          : acc,
          []
          );
          }



          zip


          zip&unzip

          • _.zip([arrays])創(chuàng)建一個(gè)打包所有元素后的數(shù)組。第一個(gè)元素包含所有提供數(shù)組的第一個(gè)元素,第二個(gè)包含所有提供數(shù)組的第二個(gè)元素,以此類推。

          • 參數(shù)[arrays] (...Array),表示要處理的數(shù)組隊(duì)列

          • 返回值 (Array)是一個(gè)打包后的數(shù)組
            _.unzip(array)類似?_.zip,接收一個(gè)打包后的數(shù)組并且還原為打包前的狀態(tài)。

          • 難度系數(shù):★

          • 建議最長(zhǎng)用時(shí):2min * 2 = 4min

          zip&unzip的例子

          var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
          // => [['fred', 30, true], ['barney', 40, false]]

          _.unzip(zipped);
          // => [['fred', 'barney'], [30, 40], [true, false]]


          參考代碼

          function zip(target, ...arrs) {
          return target.map((item, index) => [item, ...arrs.map(arr => arr[index])])
          }


          function unzip(arrs) {
          return arrs.reduce((acc, arr) => {
          arr.forEach((item, index) => {
          acc[index] = acc[index] || [];
          acc[index].push(item)
          })
          return acc
          }, [])
          }

          zipWith & unzipWith

          • _.zipWith類似?_.zip, 它另外接受一個(gè) iteratee 決定如何重組值。iteratee 會(huì)調(diào)用每一組元素,最后返回一個(gè)打包后的數(shù)組

          • _.unzipWith(array, [iteratee=_.identity])另外接受一個(gè) iteratee 來決定如何重組解包后的數(shù)組。iteratee 會(huì)傳入4個(gè)參數(shù):(accumulator, value, index, group)。每組的第一個(gè)元素作為初始化的值,返回一個(gè)解包后的數(shù)組

          • 難度系數(shù):★★

          • 建議最長(zhǎng)用時(shí):6min

          // example
          _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
          return a + b + c;
          });
          // => [111, 222]

          // unzipWith
          var zipped = _.zip([1, 2], [10, 20], [100, 200]);
          // => [[1, 10, 100], [2, 20, 200]]

          _.unzipWith(zipped, _.add);
          // => [3, 30, 300]


          參考代碼:

          // zipWith稍微修改一下就可以實(shí)現(xiàn)
          function zipWith(target, ...arrs) {
          const iteratee = arrs.pop()
          return target.map((item, index) => [item, ...arrs.map(arr => arr[index])]).map(group => iteratee(...group))
          }


          function unzipWith(arrs, iteratee) {
          // 使用唯一標(biāo)記,避免`!result`的假值誤判
          const FIRST_FLAG = Symbol()
          return arrs.reduce((acc, arr) => {
          arr.forEach((item, index) => {
          acc[index] = acc[index] || []
          acc[index].push(item)
          })
          return acc
          }, []).map(group => group.reduce((result, cur, index, all) =>
          result === FIRST_FLAG ? cur : iteratee(result, cur, index, all)
          ), FIRST_FLAG)
          }

          zipObject & zipObjectDeep

          • _.zipObject([props=[]], [values=[]]),接受屬性key的數(shù)組和values的數(shù)組,返回每一對(duì)k-v形成的對(duì)象

          • 難度系數(shù):★

          • 建議最長(zhǎng)用時(shí):2min

          //example
          _.zipObject(['a', 'b'], [1, 2]);
          // => { 'a': 1, 'b': 2 }
          function zipObject(keys, values) {
          return keys.reduce((obj, key, index) => {
          obj[key] = values[index]
          return obj
          }, {})
          }
          • _.zipObjectDeep([props=[]], [values=[]]),類似 _.zipObject,它還支持屬性路徑。

          • 難度系數(shù):★★★★

          • 建議最長(zhǎng)用時(shí):12min

          // example
          _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
          // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }


          參考代碼:

          // 從 'a'或者'[1]'這種摳出真正的key:a、1
          function getRealKey(currentKey) {
          return /\[(\d+)\]/.test(currentKey) ? RegExp.$1 : currentKey
          }

          function zipObjectDeep(keys, values) {
          return keys.reduce((obj, key, index) => {
          const path = key.split(/\.|\B(?=\[\d+\])|\b(?=\[\d+\])/)
          // 輔助變量temp,利用引用類型的特性遍歷和賦值整個(gè)對(duì)象
          let temp = obj
          // 預(yù)留一個(gè)空位,最后一下賦值
          while(path.length > 1) {
          const currentKey = path.shift()
          const realKey = getRealKey(currentKey)
          // 如果下一個(gè)是[1]這種,那么就是數(shù)組,不然就是一個(gè)對(duì)象
          // 如果你想給下一層的屬性賦值,那么就要提前準(zhǔn)備好它上一層的結(jié)構(gòu)
          temp[realKey] = temp[realKey] || (/\[(\d+)\]/.test(path[0]) ? [] : {})
          temp = temp[realKey]
          }
          // 最后一下就是賦值了
          const lastKey = getRealKey(path.shift())
          temp[lastKey] = values[index]
          return obj
          }, {})
          }

          關(guān)于正則key.split(/\.|\B(?=\[\d+\])|\b(?=\[\d+\])/)的分析:

          • split是可以傳入正則的哦,對(duì)匹配到的內(nèi)容進(jìn)行分割。除了普通的.,還要考慮類似[0]這種,這種需要匹配到邊界才可以完美分割

          • 分成3部分,.、單詞邊界+[數(shù)字]、非單詞邊界+[數(shù)字]

          • .匹配到的split一下就是?'a.b.c' => ['a', 'b', 'c']

          • 單詞邊界+[數(shù)字]?'a[1]' => ['a', '[1]']

          • 非單詞邊界+[數(shù)字]?'[0][1]' => ['[0]', '[1]']

          • ?=是正向0寬斷言,也就是說/a(?=xx)/匹配前面是xx的字符a,且xx不納入捕獲組中



          groupBy


          • _.groupBy(collection, [iteratee=_.identity])key 是經(jīng) iteratee 處理的結(jié)果, value 是產(chǎn)生 key 的元素?cái)?shù)組。iteratee 會(huì)傳入1個(gè)參數(shù):(value)。

          • 參數(shù):?collection (Array|Object)是需要遍歷的集合。[iteratee=_.identity] (Function|Object|string)是一個(gè)函數(shù),這個(gè)函數(shù)會(huì)處理每一個(gè)元素(和其他By系列的方法都是一樣的,傳入函數(shù)和With一樣的效果,傳入字符串或者數(shù)組會(huì)先調(diào)用_.property)

          • 返回一個(gè)組成匯總的對(duì)象

          • 難度系數(shù):★★(如果不知道property方法實(shí)現(xiàn),再加多兩星難度)

          • 建議最長(zhǎng)用時(shí):6min

          // example
          _.groupBy([6.1, 4.2, 6.3], Math.floor);
          // => { '4': [4.2], '6': [6.1, 6.3] }

          // 使用了 `_.property` 的回調(diào)結(jié)果
          _.groupBy(['one', 'two', 'three'], 'length');
          // => { '3': ['one', 'two'], '5': ['three'] }


          參考代碼:

          function property(path) {
          return function (o) {
          const temp = Array.isArray(path) ? path : path.split(".");
          let res = o;
          while (temp.length && res) {
          res = res[temp.shift()];
          }
          return res;
          };
          }

          function groupBy(...arrs) {
          let iteratee = arrs.pop();
          iteratee = typeof iteratee === 'function' ? iteratee : property(iteratee);
          return arrs.reduce((acc, arr) => {
          arr.forEach(item => {
          const key = iteratee(item)
          ;(acc[key] || (acc[key] = [])).push(item)
          })
          return acc
          }, {})
          }



          invokeMap


          • _.invokeMap(collection, path, [args])調(diào)用 path 的方法處理集合中的每一個(gè)元素,返回處理的數(shù)組。如果方法名是個(gè)函數(shù),集合中的每個(gè)元素都會(huì)被調(diào)用到。

          • 參數(shù):?collection (Array|Object)是需要遍歷的集合,path (Array|Function|string)是要調(diào)用的方法名 或者 這個(gè)函數(shù)會(huì)處理每一個(gè)元素。[args] (...*)給方法傳入的參數(shù)

          • 返回?cái)?shù)組結(jié)果

          • 難度系數(shù):★

          • 建議最長(zhǎng)用時(shí):3min

          // example
          _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
          // => [[1, 5, 7], [1, 2, 3]]

          _.invokeMap([123, 456], String.prototype.split, '');
          // => [['1', '2', '3'], ['4', '5', '6']]

          參考代碼:

          function invokeMap(arr, fn, ...args) {
          return arr.map(item => {
          // 面對(duì)這種傳入函數(shù)手動(dòng)調(diào)用的,都記得call/apply一下
          return (typeof fn === 'function' ? fn : arr[fn]).apply(item, args)
          })
          }


          0a6801dde959002709b7c96e6dde20d0.webp

          lodash的數(shù)組和collection的方法就此告一段落了,其他方法基本是一瞬間就可以寫出來或者沒有什么坑點(diǎn)。后面是function系列,to be continue



          往期回顧:

          內(nèi)功修煉之lodash——By、With系列


          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  99大香蕉视频 | 99黄色视屏 | JUY-579被丈夫的上司侵犯后的第7天,我 尤物网在线观看 | 爱爱中文字幕 | 色婷婷国产精品免费视频 |