Javascript Memoizer淺析
以下來自John Hann的實現(xiàn),這段代碼引起了我的注意,它用巧妙的方法把方法調(diào)用的結(jié)果緩存起來了。
代碼解析:
// memoize: 使用memoization來緩存的通用方法
// func: 要被緩存的方法
// context: 方法執(zhí)行上下文
// Note: 方法必須是外部可訪問的,參數(shù)是可字符序列化的
function memoize (func, context) {
function memoizeArg (argPos) { //參數(shù)表示原始方法中參數(shù)的位置
var cache = {}; //這個緩存的key是參數(shù),value是執(zhí)行結(jié)果
return function () { //返回一個函數(shù)閉包
if (argPos == 0) { //第一個參數(shù),如果參數(shù)在緩存的key中不存在,就執(zhí)行原始函數(shù)并且存儲執(zhí)行結(jié)果
if (!(arguments[argPos] in cache)) {
cache[arguments[argPos]] = func.apply(context, arguments);
}
return cache[arguments[argPos]];
}
else { //不是第一個參數(shù),如果參數(shù)在緩存的key中不存在,就遞歸執(zhí)行memoizeArg方法,原始方法中參數(shù)的位置-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參數(shù)的長度,javascript中用length屬性,其它的用arity屬性
return memoizeArg(arity - 1); //從最后一個參數(shù)開始遞歸
}
使用:
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));
看似簡單,再一看好像也并不易懂,可是如果能對閉包的使用比較熟悉的話,就很好理解了。經(jīng)過上面幾次mem.call的調(diào)用之后,形成的是一棵樹,每個節(jié)點都是一個閉包,每個閉包內(nèi)有一個cache,每個cache的key都是樹分支:

(注:上面圖中的“結(jié)果”也是一個閉包,只不過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];
};
}
實現(xiàn)更簡易,不過把參數(shù)push到一個數(shù)組內(nèi),再把數(shù)組當key,而key是只支持字符串型的,因此這點在使用上需要注意(比如一個對象tostring之后可能只看到”[object Object]“了),它的功能比上面那個要弱一些。
改進這一點也不難,把參數(shù)另立一個對象即可,而原cache對象和這個另立的參數(shù)對象使用一個ID關(guān)聯(lián)起來:
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];
};
}
還有一些其他的辦法,都可以寫成簡潔的函數(shù)式方法。
相關(guān)文章
Javascript計算二維數(shù)組重復(fù)值示例代碼
這篇文章主要給大家介紹了利用Javascript計算二維數(shù)組重復(fù)值的方法,文中給出了詳細的示例代碼,相信對大家的學(xué)習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。2016-12-12
axios使用攔截器統(tǒng)一處理所有的http請求的方法
這篇文章主要介紹了axios使用攔截器統(tǒng)一處理所有的http請求的方法,通過一段實例代碼給大家介紹了axios攔截器使用,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-11-11
JavaScript獲取數(shù)組最后一個元素的3種方法以及性能
在開發(fā)過程中,我們常常需要得到j(luò)s數(shù)組的最后一個數(shù)組元素,下面這篇文章主要給大家介紹了關(guān)于JavaScript獲取數(shù)組最后一個元素的3種方法以及性能,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06
js實現(xiàn)獲取最新本周周一開始的日期(單周日歷卡)
這篇文章主要為大家介紹了js實現(xiàn)獲取最新本周周一開始的日期(單周日歷卡)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10
微信小程序?qū)崿F(xiàn)展示評分結(jié)果功能
這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)展示評分結(jié)果功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-02-02
Javascript this 的一些學(xué)習總結(jié)
相信有C++、C#或Java等編程經(jīng)驗的各位,對于this關(guān)鍵字再熟悉不過了。由于Javascript是一種面向?qū)ο蟮木幊陶Z言,它和C++、C#或Java一樣都包含this關(guān)鍵字,接下來我們將向大家介紹Javascript中的this關(guān)鍵字2012-08-08
js獲取TreeView控件選中節(jié)點的Text和Value值的方法
在實際項目中,遇到一個問題,首先彈出一個新窗口,新窗口中放了一個TreeView控件,現(xiàn)在要解決的是,如何單擊TreeView中一個節(jié)點,返回Text和Value到父頁面并關(guān)閉該新窗口,本文將詳細介紹此方法的實現(xiàn)2012-11-11
JavaScript使用localStorage判斷設(shè)置值是否過期
本文主要介紹了JavaScript使用localStorage判斷設(shè)置值是否過期,通過設(shè)置過期時間,我們可以使用 setItemWithExpiration 函數(shù)將數(shù)據(jù)存儲到 localStorage 中,并使用 getItemWithExpiration 函數(shù)獲取數(shù)據(jù)并檢查是否過期,感興趣的可以了解一下2023-05-05

