DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> JavaScript工廠模式的memoizing技術
JavaScript工廠模式的memoizing技術
編輯:關於JavaScript     

網頁制作poluoluo文章簡介:最近在讀《JavaScript 設計模式》一書,其中工廠模式中提到了memoizing技術,今天仔細整理了一下memoization 相關的資料,與大家共享。

最近在讀《JavaScript 設計模式》一書,其中工廠模式中提到了memoizing技術,今天仔細整理了一下memoization 相關的資料,與大家共享。

  • Memoization的定義:

memoization 一詞是Donald Michie 根據拉丁語memorandum杜撰的一個詞。相應的動詞、過去分詞、ing形式有memoiz、memoized、memoizing.

Memoization 是一種將函數返回值緩存起來的方法,Memoization 原理非常簡單,就是把函數的每次執行結果都放入一個鍵值對(數組也可以,視情況而定)中,在接下來的執行中,在鍵值對中查找是否已經有相應執行過的值,如果有,直接返回該值,沒有才 真正執行函數體的求值部分。很明顯,找值,尤其是在鍵值對中找值,比執行函數快多了。現代 JavaScript 的開發也已經大量使用這種技術。

  •  一個簡單的使用memoization的例子

我們知道,在不同的浏覽器中,xmlHttpRequest對象的具體實現都不同。需要判斷何種浏覽器以執行具體的方法。這裡就有一個使用memoization來實現的例子。

  1. function createXHRObject = function(){
  2.     //先把三個匿名函數緩存起來。
  3.     var methods = [
  4.         function(){return new XMLHttpRequest();},
  5.         function(){return new ActiveXObject("Msxml2.XMLHTTP");},
  6.         function(){return new ActiveXObject("Microsoft.XMLHTTP");}
  7.     ];
  8.     for(var i=0,len=methods.length;i<len;i++){
  9.         try{//這裡用try catch來代替了條件判斷,通常我不贊成這種寫法
  10.             methods[i]();
  11.         }
  12.         catch(e){
  13.             continue;//如果報異常,則執行下一次循環
  14.         }
  15.         // 把createXHRObject 與能正常執行的匿名函數對應起來,再調用createXHRObject不用再檢測浏覽器了
  16.         createXHRObject = method[i];
  17.         return method[i];
  18.     }
  19. }

以上是一個簡單的例子,第一次執行createXHRObject()的時候,會循環判斷methods 中的方法,獲取一個能正確執行的,並將createXHRObject的引用指向這個方法。以後再使用這個方法的時候,不用去判斷,直接自動獲取正確的方法。這省去了頻繁的ajax調用中浏覽器的檢測。

當然,這個方法看上去效率的提升不是特別明顯,我之所以寫上來,是因為能比較清晰的理解memoization是如何實現的。在遞歸調用的時候,memoization的威力才能更好的顯現。

一個遞歸的例子

  1. function fib(n) {
  2. if (n < 2) {
  3. return n;
  4. }
  5. return fib(n - 1) + fib(n - 2);
  6. }

 這是一個經典的斐波納契序列,fib(20) 會把fib這個方法執行21891次,如果是fib(40),這會執行331160281次。

再看看如何使用memoization來實現,

  1.  var iterMemoFib = (function() {
  2.     var cache = [1, 1];
  3.     var fib = function(n) {
  4.         if (n >= cache.length) {
  5.             //將一個遞歸轉換成了一個
  6.             for (var i = cache.length; i <= n; i++) {
  7.                 cache[i] = cache[i - 2] + cache[i - 1];
  8.             }
  9.         }
  10.         return cache[n-1];
  11.     }
  12.     return fib;
  13. })();

將Function的原型擴展memoize 和unmemoize 方法,這樣你可以對任何函數實現memoize和解除memoize,當然,這個方法要慎,對一些不是頻繁執行的函數,沒必要緩存:

  1. Function.prototype.memoize = function() {
  2.     var pad  = {};
  3.     var self = this;
  4.     var obj  = arguments.length > 0 ? arguments[i] : null;
  5.  
  6.     var memoizedFn = function() {
  7.         // 把參數作為數組保存,作為鍵,把函數執行的結果作為值緩存起來
  8.         var args = [];
  9.         for (var i = 0; i < arguments.length; i++) {
  10.             args[i] = arguments[i];
  11.         }
  12.         if (!(args in pad)) {
  13.             pad[args] = self.apply(obj, arguments);
  14.         }
  15.         return pad[args];
  16.     }
  17.     memoizedFn.unmemoize = function() {
  18.         return self;
  19.     }
  20.     return memoizedFn;
  21. }
  22. Function.prototype.unmemoize = function() {
  23.     alert("Attempt to unmemoize an unmemoized function.");
  24.     return null;
  25. }
  26.  

使用方法:

fib.memoize();

參考文檔:

  1. Memoizing functions in JavaScript
  2. JavaScript Memoization
  3. 提升JS性能:將遞歸轉換為迭代
  4. MemoizationFrom Wikipedia, the free encyclopedia

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved