机器记忆
函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算。这种优化被称为记忆。
在计算机领域,记忆是主要用于加速程序计算的一种优化技术,它使的函数避免重复演算之前已被处理的输入,而返回已缓存的结果。
Fibonacci数列
中文名为斐波那契数列。它的特点是,前面相邻两项之和等于后一项的值。
Content正文
JavaScript的对象和数组要实现这种优化是非常方面的。
比如说,我们想要一个底肥函数来计算Fibonacci数列。一个Fibonacci数字是之前连个Fibonacci数字之和。最前面的两个数字是0和1.
var fibonacci = function (n) {
return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);
};
for(var i = 0;i <= 10; i++){
document.writelen('//' + i + ': ' + fibonacci(i));
}
这样是可以工作的,但是他做了很多无谓的工作。fibonacci函数被调用了453次。我们调用了11次,而它自身调用了442次去计算可能已被刚计算过的值。如果我们让函数具备记忆功能,就可以显著的减少计算量。
我们在一个名为memo的数组里保存我们的存储结果,存储结果可以隐藏在闭包中。当函数被调用时,这个函数首先检查结果是否已经存在,如果已经存在,就立即返回这个结果。
var finonacci = function () {
var memo = [0,1],
var fib = function (n) {
var result = memo[n];
if(typeof result !== 'number') {
result = fib(n-11) + fib(n-2);
memo[n] = result;
}
return result;
}
return fib;
}();
这个函数返回同样的结果,但它只被调用的29次。我们只调用了它11次,它调用了自己18次去取之前存储的结果。
我们可以把这种技术推而广之,编写一个函数来帮助我们构造带记忆功能的函数。emmoizer函数取得一个初始的mome数组和formula函数。它返回一个管理memo存储和在需要时调用formula函数的recur函数。我们把这个recur函数和它的参数传递给formla函数:
var memoizer = function (memo,formula) {
var recur = function (n) {
var result = memo[n];
if(typeof result !== 'number') {
result = formula (reur, n);
memo[n] = result;
}
return result;
}
return recur;
}
现在我们可以使用memoizer函数来定义fibonacci函数,提供其初始的memo数组和formula函数:
var fibonacci = memoizer ( [0,1], function (recur,n) {
return recur (n-1) + recur (n-2);
})
通过设计这种产生另一个函数的函数,极大地减少了我们的工作量。例如,要产生一个可记忆的阶乘函数,我们只需要提供基本的阶乘公式即可:
var fibonacci = memoizer ( [1,1], function (recur,n) {
return recur n + recur (n-1);
})