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 相关文章推荐
关于juqery radio写法的兼容性问题(新老版本jquery)
Jun 14 Javascript
js实现右下角提示框的方法
Feb 03 Javascript
js中获取jsp表单中radio类型的值简单实例
Aug 15 Javascript
前端面试题及答案整理(二)
Aug 26 Javascript
vue.js入门教程之绑定class和style样式
Sep 02 Javascript
Javascript中this关键字指向问题的测试与详解
Aug 11 Javascript
vue获取当前激活路由的方法
Mar 17 Javascript
详解Vue项目部署遇到的问题及解决方案
Jan 11 Javascript
简单谈谈javascript高级特性
Sep 04 Javascript
javascript实现动态时钟的启动和停止
Jul 29 Javascript
js中addEventListener()与removeEventListener()用法案例分析
Mar 02 Javascript
vue实现给div绑定keyup的enter事件
Jul 31 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和editplus正则表达式去除空白行
2015/04/17 PHP
Thinkphp连表查询及数据导出方法示例
2016/10/15 PHP
Laravel中validation验证 返回中文提示 全局设置的方法
2019/09/29 PHP
javascript学习笔记(十) js对象 继承
2012/06/19 Javascript
基于jquery插件实现常见的幻灯片效果
2013/11/01 Javascript
jQuery事件绑定和委托实例
2014/11/25 Javascript
JavaScript实现鼠标滑过图片变换效果的方法
2015/04/16 Javascript
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
2016/12/14 Javascript
JS跨域请求外部服务器的资源
2017/02/06 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
2017/08/10 Javascript
js 提取某()特殊字符串长度的实例
2017/12/06 Javascript
Angular4学习之Angular CLI的安装与使用教程
2018/01/04 Javascript
vue.js 微信支付前端代码分享
2018/02/10 Javascript
详解如何在Node.js的httpServer中接收前端发送的arraybuffer数据
2018/11/11 Javascript
js实现经典贪吃蛇小游戏
2020/03/19 Javascript
Vue中el-form标签中的自定义el-select下拉框标签功能
2020/04/20 Javascript
JavaScript实现沿五角星形线摆动的小圆实例详解
2020/07/28 Javascript
解决vue net :ERR_CONNECTION_REFUSED报错问题
2020/08/13 Javascript
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
在Python中使用dict和set方法的教程
2015/04/27 Python
Python中的字符串类型基本知识学习教程
2016/02/04 Python
python同时替换多个字符串方法示例
2019/09/17 Python
pyenv虚拟环境管理python多版本和软件库的方法
2019/12/26 Python
Python中sorted()排序与字母大小写的问题
2020/01/14 Python
Python之qq自动发消息的示例代码
2021/02/18 Python
纽约州一群才华横溢的金匠制作而成:Hearth Jewelry
2019/03/22 全球购物
印度电子产品购物网站:Vijay Sales
2021/02/16 全球购物
幼儿园评语大全
2014/04/17 职场文书
学校领导班子对照检查材料
2014/08/28 职场文书
党员教师批评与自我批评发言稿
2014/10/15 职场文书
聚众斗殴罪辩护词
2015/05/21 职场文书
人事任命书范本
2015/09/21 职场文书
Python中X[:,0]和X[:,1]的用法
2021/05/10 Python
Java Socket实现Redis客户端的详细说明
2021/05/26 Redis
swagger如何返回map字段注释
2021/07/03 Java/Android
Win11如何启用启动修复 ? Win11执行启动修复的三种方法
2022/04/08 数码科技