回到文章列表

    實作 javascript cache function

    TWGD / 2019-01-11 / 閱讀時間約 3 分鐘

    題目

    假設現在有一個 function 叫做 complexCalculation,裡面跑了很複雜的數學運算所以要跑很久,例如說:

    console.log(complextCalculation(10)) // 印出 123,跑了 5 秒
    console.log(complextCalculation(10)) // 印出 123,跑了 5 秒

    可是對這種運算來說,只要傳進去的參數一樣,結果就一樣,所以我可以把結果給快取起來,再跑一次 function 的時候就不用重新做這些複雜的運算,所以理想的情形下是這樣:

    var cachedComplextFunc = cached(complextCalculation)
    console.log(cachedComplextFunc(10)) // 印出 123,跑了 5 秒
    console.log(cachedComplextFunc(10)) // 立刻印出 123

    現在請你實作出 cached 這個 function,讓上面的程式碼可以順利運行

    var cachedComplextFunc = cached(complextCalculation)
    console.log(cachedComplextFunc(10)) // 印出 123,跑了 5 秒
    console.log(cachedComplextFunc(10)) // 立刻印出 123

    解題心得:

    要做到 cache 住運算結果,要運用 closure 閉包的概念。

    function cached(){} 裡面有一個 object ( cache = {} ) 用來記住之前的結果,然後 return 另一個 function 出去。 用變數 cachedComplextFunc 來接這個 return 出來的 function。 之所以可以記住變數,是因為底層 scope chain 的關係,function cached(){} 裡面的 cache 這個 object 會被 keep 住。

    一、當只有一個參數的時候:(參數是數字)

    const cached = (func) => {
      let cache = {}
      return (key) => {
        if (key in cache) {
          return cache[key]
        } else {
          let ans = func(key)
          cache[key] = ans
          return ans
        }
      }
    }

    就是把傳進來的參數當作 cache 這個 object 的 key,運算結果當作 value 給保存起來。 之後 cachedComplextFunc 有參數傳進來,若 object 有這個參數的 key,就回傳之前運算過保留的結果。 若沒有的話,就執行運算 function,然後存進 object。

    二、當有多個參數的時候:(參數都是數字)

    const cached = (func) => {
      let cache = {}
      return (...key) => {
        if (key in cache) {
          return cache[key]
        } else {
          let ans = func(...key)
          cache[key] = ans
          return ans
        }
      }
    }

    概念跟前面一樣,只是會碰到『要怎麼把多個參數傳進去?』的問題。 ES6 可以用 rest operator ...,傳進來的參數會轉成一個 array。 另外,存進去 object 的方式也是一樣把所有傳進來的參數當作 key。

    三、當參數型態除了數字也可能是字串、陣列、物件:

    const cached = (func) => {
      let cache = {}
      return (...args) => {
        let key = JSON.stringify(args)
        if (key in cache) {
          console.log('cached')
          return cache[key]
        }
        let ans = func(...args)
        cache[key] = ans
        return ans
      }
    }

    這邊會遇到 object 型態的參數無法儲存為 key 的問題。 所有 object 只會顯示 [object object]。 因此需要用 JSON.stringify() 轉換成 JSON 字串儲存。

    其他問題:字串化後,object key 的順序,造成判定成不同 object 的問題。(未完)

    重點概念整理:

    1. 應用 closure 閉包,實作 cache function。
    2. 變數產生或是有特殊符號的 object key ,只能用 obj[] 存取到。
    3. object key 只能是字串,若不是字串則會被『強制轉換』為字串。
    4. 若要傳入多個參數,ES6 可以用 Array.from(arguments) 或 ... (rest parameter) 來把參數 ( array-like ) 轉換成 array。 P.S. Arrow function 沒有自己的 arguments 物件。
    5. 若要傳入的參數型態是 object,要用 JSON.stringify() 轉換成 JSON 字串,才可以儲存。(JSON.stringify() 不能處理 function )

    參考資料: