Javascript Memoizer淺析,memoizer淺析

來源:互聯網
上載者:User

Javascript Memoizer淺析,memoizer淺析

以下來自John Hann的實現,這段代碼引起了我的注意,它用巧妙的方法把方法調用的結果緩衝起來了。

代碼解析:

複製代碼 代碼如下:
// memoize: 使用memoization來緩衝的通用方法
// func: 要被緩衝的方法
// context: 方法執行內容
// Note: 方法必須是外部可訪問的,參數是可字元序列化的
function memoize (func, context) {
    function memoizeArg (argPos) { //參數表示原始方法中參數的位置
        var cache = {}; //這個緩衝的key是參數,value是執行結果
        return function () { //返回一個函數閉包
            if (argPos == 0) { //第一個參數,如果參數在緩衝的key中不存在,就執行原始函數並且儲存執行結果
                if (!(arguments[argPos] in cache)) {
                    cache[arguments[argPos]] = func.apply(context, arguments);
                }
                return cache[arguments[argPos]];
            }
            else { //不是第一個參數,如果參數在緩衝的key中不存在,就遞迴執行memoizeArg方法,原始方法中參數的位置-1
                if (!(arguments[argPos] in cache)) {
                    cache[arguments[argPos]] = memoizeArg(argPos - 1);
                }
                return cache[arguments[argPos]].apply(this, arguments);
            }
        }
    }
    var arity = func.arity || func.length; //func參數的長度,javascript中用length屬性,其它的用arity屬性
    return memoizeArg(arity - 1); //從最後一個參數開始遞迴
}

使用:
複製代碼 代碼如下:
var mem = memoize(func, this);  
alert(mem.call(this,1,1,2));  
alert(mem.call(this,2,1,2));  
alert(mem.call(this,3,1,3));  
alert(mem.call(this,2,2,4));

看似簡單,再一看好像也並不易懂,可是如果能對閉包的使用比較熟悉的話,就很好理解了。經過上面幾次mem.call的調用之後,形成的是一棵樹,每個節點都是一個閉包,每個閉包內有一個cache,每個cache的key都是樹分支:

(註:上面圖中的“結果”也是一個閉包,只不過argPos為0而已)

不過方法有諸多,比如limboy說:

複製代碼 代碼如下:
function Memoize(fn){
    var cache = {};
    return function(){
        var key = [];
        for( var i=0, l = arguments.length; i < l; i++ )
            key.push(arguments[i]);
        if( !(key in cache) )
            cache[key] = fn.apply(this, arguments);
        return cache[key];
    };
}

實現更簡易,不過把參數push到一個數組內,再把數組當key,而key是只支援字串型的,因此這點在使用上需要注意(比如一個對象tostring之後可能只看到”[object Object]“了),它的功能比上面那個要弱一些。

改進這一點也不難,把參數另立一個對象即可,而原cache對象和這個另立的參數對象使用一個ID關聯起來:

複製代碼 代碼如下:
function Memoize(fn){
    var cache = {}, args = {};
    return function(){
        for( var i=0, key = args.length; i < key; i++ ) {
            if( equal( args[i], arguments ) )
                return cache[i];
        }
        args[key] = arguments;
        cache[key] = fn.apply(this, arguments);
        return cache[key];
    };
}

還有一些其他的辦法,都可以寫成簡潔的函數式方法。


Javascript 基礎:怎提升JavaScript的運行速度

遞迴是拖慢指令碼運行速度的大敵之一。太多的遞迴會讓瀏覽器變得越來越慢直到死掉或者莫名其妙的突然自動結束(在firefox中彈出指令碼無響應的對話方塊),所以我們一定要解決在JavaScript中出現的這一系列效能問題。在這個系列文章的第二篇中,我曾經簡短的介紹了如何通過memorization技術來替代函數中太多的遞迴調用。memoization是一種可以緩衝之前運算結果的技術,這樣我們就不需要重新計算那些已經計算過的結果。對於通過遞迴來進行計算的函數,memoization簡直是太有用了。我現在使用的memoizer是由Crockford寫的,主要應用在那些返回整數的遞迴運算中。當然並不是所有的遞迴函式都返回整數,所以我們需要一個更加通用的memoizer()函數來處理更多類型的遞迴函式。
function memoizer(fundamental, cache){ cache = cache || {} var shell = function(arg){ if (!(arg in cache)){ cache[arg] = fundamental(shell, arg) } return cache[arg]; }; return shell;}這個版本的函數和Crockford寫的版本有一點點不同。首先,參數的順序被顛倒了,原有函數被設定為第一個參數,第二個參數是緩衝對象,為選擇性參數,因為並不是所有的遞迴函式都包含初始資訊。在函數內部,我將緩衝對象的類型從數群組轉換為對象,這樣這個版本就可以適應那些不是返回整數的遞迴函式。在shell函數裡,我使用了in操作符來判斷參數是否已經包含在緩衝裡。這種寫法比測試類型不是undefined更加安全,因為undefined是一個有效傳回值。我們還是用之前提到的費伯納西數列來做說明:
var fibonacci = memoizer(function (recur, n) { return recur(n - 1) + recur(n - 2); }, {"0":0, "1":1});同樣的,執行fibonacci(40)這個函數,只會對原有的函數調用40次,而不是誇張的331,160,280次。memoization對於那些有著嚴格定義的結果集的遞迴演算法來說,簡直是棒極了。然而,確實還有很多遞迴演算法不適合使用memoization方法來進行最佳化。
我在學校時的一位教授一直堅持認為,任何使用遞迴的情況,如果有需要,都可以使用迭代來代替。實際上,遞迴和迭代經常會被作為互相彌補的方法,尤其是在另外一種出問題的情況下。將遞迴演算法轉換為迭代演算法的技術,也是和開發語言無關的。這對JavaScript來說是很重要的,因為很多東西在執行環境中是受到限制的(the importance in JavaScript is greater, though, because the resources of the execution environment are so restrictive.)。讓我們回顧一個典型的遞迴演算法,比如說歸併排序,在JavaScript中實現這個演算法需要下面的代碼:
function merge(left, right){ var result = []; while (left.length > 0 && right.length > 0){ if (left[0] < right[0]){ result.push(left.shift(......餘下全文>>
 
BestfriendMore than this,SAME OLD BRAND NEW YOU,Showmelove,stuckInMyHeartjavascript

Best friend More than this,SAME OLD BRAND NEW YOU,Show me love,stuck In My Heart javascript

勝於最好的朋友,同樣的老品牌全新的你,向我展示愛,我的心為之著迷,Java描述語言
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.