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中的其他对象
Jan 16 Javascript
javascript 打开页面window.location和window.open的区别
Mar 17 Javascript
jQuery ul标签下拉菜单演示代码
Dec 11 Javascript
获取body标签的两种方法
Oct 13 Javascript
jQuery实现背景滑动菜单
Dec 02 Javascript
js实现仿购物车加减效果
Mar 01 Javascript
浅谈小程序 setData学问多
Feb 20 Javascript
javascript中如何判断类型汇总
May 14 Javascript
微信小程序环境下将文件上传到OSS的方法步骤
May 31 Javascript
Vue 数组和对象更新,但是页面没有刷新的解决方式
Nov 09 Javascript
jquery实现图片无缝滚动 蒙版遮蔽效果
Jan 11 jQuery
django简单的前后端分离的数据传输实例 axios
May 18 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
浅谈php优化需要注意的地方
2014/11/27 PHP
js以对象为索引的关联数组
2010/07/04 Javascript
jQuery Tab插件 用于在Tab中显示iframe,附源码和详细说明
2011/06/27 Javascript
可在线编辑网页文字效果代码(单击)
2013/03/02 Javascript
jQuery之折叠面板的深入解析
2013/06/19 Javascript
JS实现的左侧竖向滑动菜单效果代码
2015/10/19 Javascript
jQuery可见性过滤选择器用法示例
2016/09/09 Javascript
利用ES6语法重构React组件详解
2017/03/02 Javascript
Vue.js手风琴菜单组件开发实例
2017/05/16 Javascript
用纯Node.JS弹出Windows系统消息提示框实例(MessageBox)
2017/05/17 Javascript
Angular2 组件间通过@Input @Output通讯示例
2017/08/24 Javascript
用nodejs实现json和jsonp服务的方法
2017/08/25 NodeJs
node.js实现的装饰者模式示例
2017/09/06 Javascript
详解JavaScript中的函数、对象
2019/04/01 Javascript
vue中更改数组中属性,在页面中不生效的解决方法
2019/10/30 Javascript
js实现小星星游戏
2020/03/23 Javascript
使用python统计文件行数示例分享
2014/02/21 Python
Pyhton中防止SQL注入的方法
2015/02/05 Python
python检测某个变量是否有定义的方法
2015/05/20 Python
Python使用matplotlib实现的图像读取、切割裁剪功能示例
2018/04/28 Python
Python实现字符型图片验证码识别完整过程详解
2019/05/10 Python
Python帮你识破双11的套路
2019/11/11 Python
解决pytorch-yolov3 train 报错的问题
2020/02/18 Python
纯css3实现的鼠标悬停动画按钮
2014/12/23 HTML / CSS
css3 仿写阿里云水纹效果的示例代码
2018/02/10 HTML / CSS
通过Canvas及File API缩放并上传图片完整示例
2013/08/08 HTML / CSS
用HTML5制作视频拼图的教程
2015/05/13 HTML / CSS
HSRP的含义以及如何工作
2014/09/10 面试题
高三英语教学反思
2014/01/13 职场文书
上课迟到检讨书
2014/01/19 职场文书
大学生开西餐厅创业计划书
2014/02/01 职场文书
迎元旦广播稿
2014/02/22 职场文书
《匆匆》教学反思
2014/02/22 职场文书
新闻传媒系求职信范文
2014/04/19 职场文书
怎么禁用Windows 11快照布局? win11不使用快照布局的技巧
2021/11/21 数码科技
基于Apache Hudi在Google云构建数据湖平台的思路详解
2022/04/07 Servers