數(shù)組扁平化,柯里化,防抖,節(jié)流,對(duì)象拷貝

數(shù)組扁平化

數(shù)組扁平化:使用遞歸實(shí)現(xiàn)
function flattenDepth(array, depth=1) {
    let result = [];
    array.forEach (item => {
      let d = depth;
      if(Array.isArray(item) && d > 0){
          result.push(...(flattenDepth(item, --d)))
      } else {
          result.push(item);
      }
})
    return result;
}
console.log(flattenDepth([1,[2,[3,[4]],5]]))
console.log(flattenDepth([1,[2,[3,[4]],5]],2))
console.log(flattenDepth([1,[2,[3,[4]],5]],3))

將每一項(xiàng)遍歷,如果某一項(xiàng)為數(shù)組,則讓該項(xiàng)繼續(xù)調(diào)用,這里指定了depth作為扁平化的深度,因?yàn)檫@個(gè)參數(shù)對(duì)數(shù)組的每一項(xiàng)都要起作用。

柯里化

參數(shù)夠了就執(zhí)行,參數(shù)不夠就返回一個(gè)函數(shù),之前的參數(shù)存起來,直到夠了為止。

function curry(func) {
   var l = func.length;
    return function curried() {
        var args = [].slice.call(arguments);
         if(args.length < l) {
              return function() {
                  var argsInner = [].slice.call(arguments)
                   return curried.apply(this, args.concat(argsInner))
              }
          } else {
            return func.apply(this, args)
          }
    }
}

var f = function(a,b,c) {
  return console.log([a,b,c])
}
var curried = curry(f);
curried(1)(2)(3)
節(jié)流和防抖

函數(shù)節(jié)流和函數(shù)防抖都是對(duì)大量頻繁調(diào)用代碼的一種優(yōu)化。

防抖

不管你觸發(fā)了多少次,都等到你最后觸發(fā)后過一段你指定的時(shí)間才觸發(fā)。簡(jiǎn)單地說,即函數(shù)在特定的時(shí)間內(nèi)不被再調(diào)用后執(zhí)行。

  • 實(shí)際應(yīng)用場(chǎng)景:監(jiān)聽窗口大小重繪的操作

在用戶拖拽窗口時(shí),一直在改變窗口的大小,如果我們?cè)?resize 事件中進(jìn)行一些操作,消耗將是巨大的。而且大多數(shù)可能是無意義的執(zhí)行,因?yàn)橛脩暨€處于拖拽的過程中。可以使用 函數(shù)防抖 來優(yōu)化相關(guān)的處理。

 // 普通方案
 window.addEventListener('resize', () => {
    console.log('trigger');
 })

//函數(shù)防抖方案
let debounceIdentify = 0;
  window.addEventListener('resize', () => {
      debounceIdentify && clearTimeout(debounceIdentity)
      debounceIdentity = setTimeout(() => {
            console.log('trigger')
       }, 300)
})

我們?cè)?resize 事件中添加了一個(gè) 300 ms 的延遲執(zhí)行邏輯。
并且每次事件觸發(fā)時(shí),都會(huì)重新計(jì)時(shí),這樣保證,函數(shù)的執(zhí)行肯定是在距離上次 resize 事件被觸發(fā)的 300 ms 后。兩次 resize 事件間隔小于 300 ms 的都被忽略了,這樣就會(huì)節(jié)省很多無意義的事件觸發(fā)。

  • 輸入框的聯(lián)想

幾乎所有的搜索引擎都會(huì)對(duì)你輸入的文字進(jìn)行預(yù)判,并在下方推薦相關(guān)的結(jié)果。但是這個(gè)聯(lián)想意味著我們需要將當(dāng)前用戶所輸入的文本傳遞到后端,并獲取返回?cái)?shù)據(jù),展示在頁面中。如果遇到打字速度快的人,在一小段時(shí)間內(nèi),會(huì)連續(xù)發(fā)送大量的 ajax 請(qǐng)求到后端。并且當(dāng)前的數(shù)據(jù)返回過來后,其實(shí)已經(jīng)失去了展示的意義,因?yàn)橛脩艨赡軓?you 輸入到了 young ,這兩個(gè)單詞的相關(guān)結(jié)果肯定不一樣的。所以我們就在監(jiān)聽用戶輸入的事件那里做函數(shù)防抖處理,在 XXX 秒后發(fā)送聯(lián)想搜索的 ajax 請(qǐng)求。

  /**
   * 函數(shù)防抖的實(shí)現(xiàn)
   * @param  {Function} func   要實(shí)現(xiàn)函數(shù)節(jié)流的原函數(shù)
   * @param  {Number}   delay  結(jié)束的延遲時(shí)間
   * @return {Function}        添加節(jié)流功能的函數(shù)
  */

function debounce (func, delay) {
   let debounceIdentify = 0
   return (...args) => {
   debounceIdentify && clearTimeout(debounceIdentify)
      debounceIdentify = setTimeout(() => {
      debounceIdentify = 0
      func.apply(this, args)
    }, delay)
   }
}
  • 基本版的:

    function debounce(func, wait){
     var timer;
     return function(){
       var context = this;
       var args = arguments;
       clearTimeout(timer);
       timer = setTimeout(function(){
           func.apply(context, args)
       }, wait)
     }
    }
    function debounce(func, wait, leading, trailing) {
        var timer, lastCall = 0, flag = true
        return function() {
            var context = this
            var args = arguments
            var now = + new Date()
            if (now - lastCall < wait) {
                flag = false
                lastCall = now
            } else {
                flag = true
           }
      if (leading && flag) {
            lastCall = now
            return func.apply(context, args)
       }
      if (trailing) {
          clearTimeout(timer)
             flag = true
             func.apply(context, args)
         }, wait)
       }
     }
    }
    
  • 類似函數(shù)防抖操作

在一些與用戶的交互上,比如提交表單后,一般都會(huì)顯示一個(gè)loading框來提示用戶,他提交的表單正在處理中。但是發(fā)送表單請(qǐng)求后就顯示loading是一件很不友好的事情,因?yàn)檎?qǐng)求可能在幾十毫秒內(nèi)就會(huì)得到響應(yīng)。
這樣在用戶看來就是頁面中閃過一團(tuán)黑色,所以可以在提交表單后添加一個(gè)延遲函數(shù),在XXX秒后再顯示loading框。這樣在快速響應(yīng)的場(chǎng)景下,用戶是不會(huì)看到一閃而過的loading框,當(dāng)然,一定要記得在接收到數(shù)據(jù)后去clearTimeout.

 let identify = setTimeout(showLoadingModal, 500)
    fetch('XXX').then(res => {
    // doing something

    // clear timer
    clearTimeout(identify)
})
  • 節(jié)流

不管怎么觸發(fā),都是按照指定的時(shí)間間隔來執(zhí)行。簡(jiǎn)單地說,就是限制函數(shù)在一定時(shí)間內(nèi)調(diào)用的次數(shù)。在程序中,可以通過限制函數(shù)的調(diào)用頻率,來抑制資源的消耗。需要實(shí)現(xiàn)一個(gè)元素拖拽的效果,可以在每次 move 事件中進(jìn)行重繪 DOM,但是這樣做,程序的開銷是非常大的。所以這里用到函數(shù)節(jié)流的方法,來減少重繪的次數(shù)。

 //普通方案
$dragable.addEventListener('mousemove', () => {
    console.log('trigger')
})

// 函數(shù)節(jié)流的實(shí)現(xiàn)方案
let throttleIndentify = 0;
$dragable.addEventListener('mousemove', () => {
    if(throttleIndentify) return;
    throttleIndentify = setTimeout(() => throttleIdentify = 0, 500);
    console.log('trigger');
})

這樣做的效果是,在拖拽的過程中,能保證 500 ms 內(nèi),只能重繪一次 DOM。 在同時(shí)監(jiān)聽了 mousemove 后,兩者最終的效果是一致的,但是在拖拽的過程中,函數(shù)節(jié)流 版觸發(fā)事件的次數(shù)會(huì)減少很多,資源相應(yīng)地會(huì)消耗更少。

通用的函數(shù)節(jié)流實(shí)現(xiàn)

// ES6 版
function throttle (func, interval) {
    let identify = 0;
    return (...args) => {
          if (identify) return;
          identify = setTimeout(() => identify = 0, interval);
         func.apply(this, args)
   }
}
function throttle(func, wait){
    var timer;
    return function() {
    var context = this;
    var args = arguments;
   if(!timer) {
        timer = setTimeout(function() {
        timer = null;
        func.apply(context, args)
      },wait)
    }
  }
}
function throttle(func, wait, leading, trailing) {
    var timer, lastCall = 0, flag = true
    return function() {
      var context = this
      var args = arguments
      var now = + new Date()
      flag = now - lastCall > wait
      if (leading && flag) {
          lastCall = now
          return func.apply(context, args)
      }
      if (!timer && trailing && !(flag && leading)) {
          timer = setTimeout(function () {
              timer = null
              lastCall = + new Date()
              func.apply(context, args)
          }, wait)
      } else {
      lastCall = now
    }
  }
}
  • 類似函數(shù)節(jié)流的操作

平時(shí)開發(fā)中經(jīng)常會(huì)做的 ajax 請(qǐng)求獲取數(shù)據(jù),這里可以用到類似函數(shù)節(jié)流的操作。在我們發(fā)送一個(gè)請(qǐng)求到后臺(tái)時(shí),當(dāng)返回的數(shù)據(jù)還沒有接收到,我們會(huì)添加一個(gè)標(biāo)識(shí),來表明當(dāng)前有一個(gè)請(qǐng)求正在被處理,如果這時(shí)用戶再觸發(fā) ajax 請(qǐng)求,則會(huì)直接跳過本次函數(shù)的執(zhí)行。同樣的還有滑動(dòng)加載更多數(shù)據(jù),如果不添加類似的限制,可能會(huì)導(dǎo)致發(fā)送更多條請(qǐng)求,渲染重復(fù)數(shù)據(jù)。

  • 對(duì)象拷貝

  • 對(duì)象拷貝分為深拷貝淺拷貝

    JSON.parse(JSON.stringify(obj))
    function clone(value, isDeep) {
        if(value === null) return null;
        if(typeof value !== 'object') return value
        if(Array.isArray(value)) {
           if(isDeep) {
              return value.map(item => clone(item, true))    
            }
          return [].concat(value)
      } else {
          if(isDeep) {
              var obj = {};
              Object.keys(value).forEach(item => {
                  obj[item] = clone(value[item], true)
                })
              return obj;
          }
      return {...value}
      }
    }
    
    var objects = { c: { 'a': 1, e: [1, {f: 2}] }, d: { 'b': 2 } }
    var shallow = clone(objects, true)
    console.log(shallow.c.e[1]) // { f: 2 }
    console.log(shallow.c === objects.c) // false
    console.log(shallow.d === objects.d) // false
    console.log(shallow === objects) // false
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,870評(píng)論 0 38
  • 長(zhǎng)久以來,面向?qū)ο笤?JavaScript 編程范式中占據(jù)著主導(dǎo)地位。不過,最近人們對(duì)函數(shù)式編程的興趣正在增長(zhǎng)。函...
    神刀閱讀 480評(píng)論 0 0
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 7,798評(píng)論 2 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,785評(píng)論 18 139
  • 大家晚上好,我是耐心,今天自己做魚,我愛我自己,今天晚上吃飯了火鍋粉,我愛我自己,今天打了桌球,我愛我自己,耐心,我愛你
    心羽暖姐姐閱讀 150評(píng)論 0 0