JS 利用高階函數實現函數緩存(備忘模式)

1. 高階函數

高階函數就是那種輸入參數裏面有一個或者多個函數,輸出也是函數的函數,這個在js裏面主要是利用閉包實現的,最簡單的就是常常看到的在一個函數內部輸出另外一個函數,好比前端

var test = function() {
    return function() {}
}

這個主要是利用閉包來保持着做用域:segmentfault

var add = function() {
    var num = 0;
    return function(a) {
        return num = num + a;
    }
}
add()(1);      // 1
add()(2);      // 2

這裏的兩個add()(1)和add()(2)不會互相影響,能夠理解爲每次運行add函數後返回的都是不一樣的匿名函數,就是每次add運行後return的function其實都是不一樣的,因此運行結果也是不會影響的。數組

若是換一種寫法,好比:緩存

var add = function() {
    var num = 0;
    return function(a) {
        return num = num + a;
    }
}
var adder = add();
adder(1); // 1
adder(2); // 3

這樣的話就會在以前運算結果基礎上繼續運算,意思就是這兩個 adder 運行的時候都是調用的同一個 num微信

2. 高階函數實現緩存(備忘模式)

好比有個函數:閉包

var add = function(a) {
    return a + 1;
}

每次運行add(1)的時候都會輸出2,可是輸入1每次仍是會計算一下1+1,若是是開銷很大的操做的話就比較消耗性能了,這裏其實能夠對這個計算進行一次緩存。
因此這裏能夠利用高階函數的思想來實現一個簡單的緩存,我能夠在函數內部用一個對象存儲輸入的參數,若是下次再輸入相同的參數,那就比較一下對象的屬性,把值從這個對象裏面取出來。app

const memorize = function(fn) {
  const cache = {}
  return function(...args) {
    const _args = JSON.stringify(args)
    return cache[_args] || (cache[_args] = fn.apply(fn, args))
  }
}
const add = function(a) {
  return a + 1
}
const adder = memorize(add)
adder(1)    // 2    cache: { '[1]': 2 }
adder(1)    // 2    cache: { '[1]': 2 }
adder(2)    // 3    cache: { '[1]': 2, '[2]': 3 }

JSON.stringify把傳給 adder 函數的參數變成了字符串,而且把它當作 cache 的 key,將 add 函數運行的結果當作 value 傳到了 cache 裏面,這樣 memorize 的匿名函數運行的時候會返回cache[_args],若是cache[_args]不存在的話就返回fn.apply(fn,args),把fn.apply(fn, arguments)賦值給cache[_args]並返回。
注意:cache不能夠是Map,由於Map的鍵是使用===比較的,[1]!==[1],所以即便傳入相同的對象或者數組,那麼仍是被存爲不一樣的鍵。函數

const memorize = function(fn) {        //  X 錯誤示範
  const cache = new Map()
  return function(...args) {
    return cache.get(args) || cache.set(args, fn.apply(fn, args)).get(args)
  }
}
const add = function(a) {
  return a + 1
}
const adder = memorize(add)
adder(1)    // 2    cache: { [ 1 ] => 2 }
adder(1)    // 2    cache: { [ 1 ] => 2, [ 1 ] => 2 }
adder(2)    // 3    cache: { [ 1 ] => 2, [ 1 ] => 2, [ 2 ] => 3 }

本文是系列文章,能夠相互參考印證,共同進步~性能

  1. JS 抽象工廠模式
  2. JS 工廠模式
  3. JS 建造者模式
  4. JS 原型模式
  5. JS 單例模式
  6. JS 回調模式
  7. JS 外觀模式
  8. JS 適配器模式
  9. JS 利用高階函數實現函數緩存(備忘模式)
  10. JS 狀態模式
  11. JS 橋接模式
  12. JS 觀察者模式

網上的帖子大多深淺不一,甚至有些先後矛盾,在下的文章都是學習過程當中的總結,若是發現錯誤,歡迎留言指出~學習

參考: <JavaScript模式>P78

PS:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~

另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~

相關文章
相關標籤/搜索