函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算。这种优化被称为记忆。
最近读javascript语言精粹这本书函数章节的时候,里面有个记忆函数的优化,书中给的栗子是斐波那契数列执行的时候减少调用次数的优化,那么这种优化能在哪些场景使用呢?
在看书中的栗子之前,我们先看一个栗子:
var memorize = function(f,hasher){
var memoize = function(name){
var cache = memoize.cache;
var key = "" + (hasher ? hasher.apply(this,arguments):name)
if(!cache[key]){
cache[key] = f.apply(this,arguments);
}
return cache[key];
}
memoize.cache = {};
return memoize;
}
function add(a,b){
return a+b;
}
var memorizedAdd = memorize(add,function(){
var args = Array.prototype.slice.call(arguments);
return JSON.stringify(args);
});
console.time("使用函数记忆执行时间");
for(var i = 0; i < 10000;i++){
memorizedAdd(1,2);
}
console.timeEnd("使用函数记忆执行时间");
console.time("原生调用执行时间");
for(var i = 0; i < 10000;i++){
add(1,2);
}
console.timeEnd("原生调用执行时间");
//使用函数记忆执行时间: 15.49462890625ms
//原生调用执行时间: 0.962890625ms
上面的memoize方法来自underscore源码,这说明函数记忆并不是万能的。
在看看斐波那契数列的栗子:
var count = 0;
var fibonacci = function(n){
count++;
return n< 2 ? n : fibonacci(n-1) + fibonacci(n-2);
}
for(var i = 0; i <= 10;i++){
fibonacci(i);
}
console.log(count);//453
fibonacci = memorize(fibonacci);
for(var i = 0; i <= 10;i++){
fibonacci(i);
}
console.log(count);//12
使用了函数记忆,调用次数从453次减少到了12次。