首頁 >web前端 >js教程 >Javascript Memoizer淺析_javascript技巧

Javascript Memoizer淺析_javascript技巧

WBOY
WBOY原創
2016-05-16 16:33:551239瀏覽

以下來自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             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             if( equal( args[i], arguments ) )
                return cache[i];
        }
        args[key] = arguments;
        cache[key] = fn.apply(this, arguments);
        return cache[key];
    };
}

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

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn