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 相关文章推荐
jQuery源码分析-01总体架构分析
Nov 14 Javascript
javascript开发随笔二 动态加载js和文件
Nov 25 Javascript
jQuery动态添加 input type=file的实现代码
Jun 14 Javascript
js获取通过ajax返回的map型的JSONArray的方法
Jan 09 Javascript
node爬取微博的数据的简单封装库nodeweibo使用指南
Jan 02 Javascript
基于JS实现移动端访问PC端页面时跳转到对应的移动端网页
Dec 24 Javascript
jQuery EasyUI开发技巧总结
Sep 26 jQuery
elementui的默认样式修改方法
Feb 23 Javascript
vue 刷新之后 嵌套路由不变 重新渲染页面的方法
Sep 13 Javascript
详解Webpack如何引入CDN链接来优化编译后的体积
Jun 21 Javascript
layui table数据修改的回显方法
Sep 04 Javascript
JavaScript语法约定和程序调试原理解析
Nov 03 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 实用代码收集
2010/01/22 PHP
实现在同一方法中获取当前方法中新赋值的session值解决方法
2014/06/26 PHP
实例介绍PHP的Reflection反射机制
2014/08/05 PHP
php使用curl通过代理获取数据的实现方法
2016/05/16 PHP
Jquery 快速构建可拖曳的购物车DragDrop
2009/11/30 Javascript
自定义jQuery选项卡插件实例
2013/03/27 Javascript
Jquery带搜索框的下拉菜单
2013/05/06 Javascript
js模拟select下拉菜单控件的代码
2013/05/08 Javascript
Javascript 按位与运算符 (&amp;)使用介绍
2014/02/04 Javascript
深入剖析JavaScript中的枚举功能
2014/03/06 Javascript
jquery 自定义容器下雨效果可将下雨图标改为其他
2014/04/23 Javascript
js中document.write的那点事
2014/12/12 Javascript
基于javascript实现右下角浮动广告效果
2016/01/08 Javascript
浅析BootStrap模态框的使用(经典)
2016/04/29 Javascript
javascript url几种编码方式详解
2016/06/06 Javascript
angularjs中ng-bind-html的用法总结
2017/05/23 Javascript
使用Vuex实现一个笔记应用的方法
2018/03/13 Javascript
vue-router命名视图的使用讲解
2019/01/19 Javascript
jquery实现选项卡切换代码实例
2019/05/14 jQuery
vue页面加载时的进度条功能(实例代码)
2020/01/13 Javascript
Vue $attrs &amp; inheritAttr实现button禁用效果案例
2020/12/07 Vue.js
[48:53]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS VG第一场
2014/05/26 DOTA
使用python 获取进程pid号的方法
2014/03/10 Python
python根据unicode判断语言类型实例代码
2018/01/17 Python
Right-on官方网站:日本知名的休闲服装品牌
2019/07/12 全球购物
大学生大二自我鉴定
2013/10/28 职场文书
总经理岗位职责描述
2014/02/08 职场文书
任命书怎么写
2014/06/04 职场文书
医院搬迁方案
2014/06/14 职场文书
普通话宣传标语
2014/06/26 职场文书
中秋节国旗下演讲稿
2014/09/05 职场文书
2015新员工试用期工作总结
2014/12/12 职场文书
JavaScript+HTML实现学生信息管理系统
2021/04/20 Javascript
python实现三阶魔方还原的示例代码
2021/04/28 Python
tomcat的catalina.out日志按自定义时间格式进行分割的操作方法
2022/04/02 Servers
Spring IOC容器Bean的作用域及生命周期实例
2022/05/30 Java/Android