函数可以使用对象去记住先前操作的结果,从而避免多余的运算。
比如我们现在测试一个费波纳茨算法,我们可以使用递归函数计算fibonacci数列,一个fibonacci数字是之前两个fibonacci数字之和,最前面的两个数字是0和1。代码如下:
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+=1) { console.log(i+":"+fibonacci(i)); } console.log(count); // 453
我们可以看到如上 fibonacci函数总共调用了453次,for循环了11次,它自身调用了442次,如果我们使用下面的记忆函数的话,那么就可以减少他们的运算次数,从而提高性能。
思路:先使用一个临时数组保存存储结果,当函数被调用的时候,先查找是否已经有存储结果,如果有的话,就立即返回这个存储结果,没有的话,调用函数进行运算。代码如下:
1 var count2 = 0; 2 var fibonacci2 = (function(){ 3 var memo = [0,1]; 4 var fib = function(n) { 5 var result = memo[n]; 6 count2++; 7 if(typeof result !== ‘number‘) { 8 result = fib(n-1) + fib(n-2); 9 memo[n] = result; 10 } 11 return result; 12 }; 13 return fib; 14 })(); 15 for(var j = 0; j <= 10; j+=1) { 16 console.log(j+":"+fibonacci2(j)); 17 } 18 console.log(count2); // 29
这个函数也返回了同样的结果,但是只调用了函数29次,循环了11次,也就是说函数自身调用了18次,从而减少无谓的函数的调用及运算,下面我们可以把这个函数进行抽象化,以构造带记忆功能的函数,如下代码:
1 var count3 = 0; 2 var memoizer = function(memo,formula) { 3 var recur = function(n) { 4 var result = memo[n]; 5 count3++; // 这句代码只是说明运行函数多少次,在代码中并无作用,实际使用上可以删掉 6 if(typeof result !== ‘number‘) { 7 result = formula(recur,n); 8 memo[n] = result; 9 } 10 return result; 11 }; 12 return recur; 13 }; 14 var fibonacci3 = memoizer([0,1],function(recur,n){ 15 return recur(n-1) + recur(n-2); 16 }); 17 // 调用方式如下 18 for(var k = 0; k <=10; k+=1) { 19 console.log(k+":"+fibonacci3(k)); 20 } 21 console.log(count3); // 29
如上封装 memoizer 里面的参数是实现某个方法的计算公式,具体的可以根据需要自己手动更改,这里的思路无非就是想习惯使用对象去保存临时值,从而减少不必要的取值存储值的操作;
学习资源:理解使用函数实现历史记录--提高性能
时间: 2024-11-13 01:20:23