Javascript Memoizer浅析


Posted in Javascript onOctober 16, 2014

以下来自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都是树分支:

Javascript Memoizer浅析

(注:上面图中的“结果”也是一个闭包,只不过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使用include/require
Nov 13 Javascript
js在IE与firefox的差异集锦
Nov 11 Javascript
jQuery获得指定元素坐标的方法
Apr 14 Javascript
Javascript实现颜色rgb与16进制转换的方法
Apr 18 Javascript
js实现的万能flv网页播放器代码
Apr 30 Javascript
Jquery和JS获取ul中li标签的实现方法
Jun 02 Javascript
jQuery动态追加页面数据以及事件委托详解
May 06 jQuery
详解vue-router 2.0 常用基础知识点之router-link
May 10 Javascript
js禁止浏览器页面后退功能的实例(推荐)
Sep 01 Javascript
JavaScript自执行函数和jQuery扩展方法详解
Oct 27 jQuery
JavaScript(js)处理的HTML事件、键盘事件、鼠标事件简单示例
Nov 19 Javascript
解决VueCil代理本地proxytable无效报错404的问题
Nov 07 Javascript
让JavaScript和其它资源并发下载的方法
Oct 16 #Javascript
JavaScript实现继承的4种方法总结
Oct 16 #Javascript
JavaScript实现网页截图功能
Oct 16 #Javascript
JavaScript跨域方法汇总
Oct 16 #Javascript
js阻止事件追加的具体实现
Oct 15 #Javascript
用原生js做个简单的滑动效果的回到顶部
Oct 15 #Javascript
原生的html元素选择器类似jquery选择器
Oct 15 #Javascript
You might like
DW中链接mysql数据库时,建立字符集中文出现乱码的解决方法
2010/03/27 PHP
PHPnow安装服务[apache_pn]失败的问题的解决方法
2010/09/10 PHP
php中检查文件或目录是否存在的代码小结
2012/10/22 PHP
php读取本地文件常用函数(fopen与file_get_contents)
2013/09/09 PHP
Smarty日期时间操作方法示例
2016/11/15 PHP
YII框架实现自定义第三方扩展操作示例
2019/04/26 PHP
jquery $.ajax()取xml数据的小问题解决方法
2010/11/20 Javascript
分享几个超级震憾的图片特效
2012/01/08 Javascript
js事件(Event)知识整理
2012/10/11 Javascript
javascript类型转换使用方法
2014/02/08 Javascript
jQuery控制Div拖拽效果完整实例分析
2015/04/15 Javascript
JavaScript tab选项卡插件实例代码
2016/02/23 Javascript
JS防止网页被嵌入iframe框架的方法分析
2016/09/13 Javascript
jquery+css3问卷答题卡翻页动画效果示例
2016/10/26 Javascript
JS实现图片放大缩小的方法
2017/02/15 Javascript
详解Vue CLI3 多页应用实践和源码设计
2018/08/30 Javascript
在layer弹层layer.prompt中,修改placeholder的实现方法
2019/09/27 Javascript
vue实现弹幕功能
2019/10/25 Javascript
[01:50]《我与DAC》之玩家:iG夺冠时的那面红旗
2018/03/29 DOTA
[05:40]DOTA2荣耀之路6:Wings最后进攻
2018/05/30 DOTA
pytorch 图像中的数据预处理和批标准化实例
2020/01/15 Python
python实现拼图小游戏
2020/02/22 Python
django实现将后台model对象转换成json对象并传递给前端jquery
2020/03/16 Python
python GUI模拟实现计算器
2020/06/22 Python
Python 程序报错崩溃后如何倒回到崩溃的位置(推荐)
2020/06/23 Python
用OpenCV进行年龄和性别检测的实现示例
2021/01/29 Python
基于Pytorch版yolov5的滑块验证码破解思路详解
2021/02/25 Python
用css3制作纸张效果(外翻卷角)
2013/02/01 HTML / CSS
用CSS3写的模仿iPhone中的返回按钮
2015/04/04 HTML / CSS
行政人员岗位职责
2013/12/08 职场文书
新闻编辑自荐书范文
2014/02/12 职场文书
募捐倡议书
2014/04/14 职场文书
推荐信格式范文
2014/05/09 职场文书
意向书范本
2014/07/29 职场文书
初中体育课教学反思
2016/02/16 职场文书
JavaScript canvas实现流星特效
2021/05/20 Javascript