转贴: Realazy » JavaScript Memoization

牛人啊。转贴一下顺便试试网易的一键转贴

这小段代码就有很多技术要点:http://realazy.org/lab/memoization.html (看源代码)

1.function的call和apply方法就不用说了,注意第一个参数是对象,后面是调用参数。

2.var obj = obj || window, func = obj[func], cache = {};一句给三个对象赋值。第一个是用||来保证非空,否则用window对象。第二个是所谓的关联数组(见js参考文档)。第三个则是空Array.

关联数组:

将对象作为关联数组

通常,使用点运算符“.”访问对象的属性。例如,

myObject.aProperty

在这里,属性名称是一个标识符。也可以用索引运算符“[]”访问对象的属性。在这里,是把对象看作一个关联数组。关联数组是一种数据结构,它可以动态地将任意的数据的值与任意的字符串相关联。例如,

myObject["aProperty"] // 与上面相同。
3.Array.prototype.join.call(arguments, '_');
这里用来Array.join,但又不是构造一个Array后再用join,而是直接使用prototype的方法函数,使用这个函数对象的call
方法(也即是Array对象的prototype成员的join方法作为Function对象来调用call方法,真绕)
为什么不能直接用arguments.join('_')呢,因为arguments是一个专门的对象,和Array一样,但只有length,[0...n]和callee三个方法和属性
但他既然用了join.call,那么arguments作为ThisObject,或者说scope来调用join方法,也就是说arguments可以转化为支持join的Array对象,
那么这个转化又是怎么发生的呢?是系统调用了Array的构造函数吗?可是我用(new Array(arguments)).join('_')却为什么不行呢?仔细看看
new Array(arguments)得到的对象,虽然是一个array,但里面的每一个元素却是Object(从watch中看到的),但是看看JS应该是弱类型的,也就
是说join可以接受Array中的元素不是字符串,它会自己调用Object.toString(),甚至在参考文档中join方法的示例里的Array元素也并非字符串。
可为什么(new Array(arguments)).join('_')不行呢?
补充:最后终于发现,是因为Array的构造函数不接受单个的Array或arguments对象作为参数,单个参数只能做单个元素,它不会展开放进去。。。所以,这也就说明prototype.join.call是直接接收arguments对象但使用了它的length,[index]等Array到方法,却没有调用new构造函数来转换,如果JS真的是面向对象的语言而这种转换却没有使用new,那么只有一个结论:Arguments对象和Array对象有继承关系。而如果JS不是严格的OO语言地实现其语法,那么是有可能可以直接通过关联数组之类的实现来调用拥有的方法而不需要对象真的是Array...
 
以下为原文转贴:

JavaScript Memoization

写于 2008年4月22日,在JavaScript / Dom分类下

Memoization 是一种将函数返回值缓存起来的方法,在 Lisp, Ruby, Perl, Python 等语言中使用非常广泛。随着 Ajax 的兴起,客户端对服务器的请求越来越密集(经典如 autocomplete),如果有一个良好的缓存机制,那么客户端 JavaScript 程序的效率的提升是显而易见的。

Memoization 原理非常简单,就是把函数的每次执行结果都放入一个散列表中,在接下来的执行中,在散列表中查找是否已经有相应执行过的值,如果有,直接返回该值,没有才真正执行函数体的求值部分。很明显,找值,尤其是在散列中找值,比执行函数快多了。现代 JavaScript 的开发也已经大量使用这种技术。

我通过 Google 寻找了好几种 JavaScript Memoization 的实现,都不太如人愿,有的实现不能缓存递归函数,有的需要修改函数的 prototype,于是自己实现一个:

/** * JavaScript Momoization * @param {string} func name of function / method * @param {object} [obj] mothed's object or scope correction object * * MIT / BSD license */ function Memoize(func, obj){ var obj = obj || window, func = obj[func], cache = {}; return function(){ var key = Array.prototype.join.call(arguments, ""); var key = Array.prototype.join.call(arguments, "_") if (!(key in cache)) cache[key] = func.apply(obj, arguments); return cache[key]; } }

并写了一个测试案例,空口无凭,让大家亲自看看 Memoization 的威力。

另,例子中的 fibonacci 函数有很多更有效率的实现方法,在此我使用最无效率的递归实现,只是为了更直达地演示 memoization.

longwosion

多参数时,用那样的方式形成key的话不能保证唯一性。比如,我们要写一个下面的组合函数的话。

var comm = {
comm: function(m, n) {
if(n==0) return 1;
if(m==n) return 1;
if(n==1) return m;
return this.comm(m-1,n) + this.comm(m-1,n-1);
},

comm_memo: function(m, n) {
if(n==0) return 1;
if(m==n) return 1;
if(n==1) return m;
return this.comm_memo(m-1,n) + this.comm_memo(m-1,n-1);
}
}

comm.comm_memo = Memoize(’comm_memo’, comm);

下面两组参数会获得一样的结果,显然是不对的。

[221,3]
[22,13]

fcicq

求 fib(n)? 乱吵一下, 当个小总结.

1 应该使用尾递归, 只是加一个参数…
2 应该使用矩阵乘法, 可以在 O(logn) 的时间内…
or 用这个结论
fib(2n) = fib(n-1)*fib(n) + fib(n)*fib(n+1)
fib(2n+1) = fib(n)^2 + fib(n+1)^2
fib(2n-1) = fib(n-1)^2 + fib(n)^2

ps: 楼上这位的程序, 也有相当大的优化空间.

Lunatic Sun

@longwosion - 你的建议不错。

另外,不递归的话不能够提升效率吧,如果cache能够成为obj的私有属性或许不递归也能提升效率。

魏中华

>>随着 Ajax 的兴起,客户端对服务器的请求越来越密集(经典如 autocomplete),如果有一个良好的缓存机制,那么客户端 JavaScript 程序的效率的提升是显而易见的。

既然需求是解决服务器请求过多的问题,那么直接缓存 Ajax 请求(URL + get/post 的数据)的结果应该可以解决问题,直接缓存函数貌似太复杂了。

zamanewby

帅! 前些日子还在想, 怎么能在前端做个很好的cache。 发现一些开源框架会缓存住selector取得的元素信息, 以为自己能做的只是尽可能缓存取来的数据。 这个利用闭包缓存住函数执行结果的方法提供了新的思路, 很赞:)

arthuridea

现在的前端开发对于程序的效率越来越高也越来越体系化了。。。
不错,学习中。。

有想法?欢迎留言:

· 留言板 · 关于 · XHTML · CSS · WordPress · jQuery · 京ICP备06034147号




引文来源   Realazy » JavaScript Memoization
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值