JavaScript闭包是学习JavaScript高级的必经之路。所以为了能够更好的理解闭包,记录一下关于闭包的几个小案例。Fibonacci函数是我们比较熟悉的函数了,一般我们是使用递归的方法去实现的。但是大家都知道,递归其实是对二叉树的深度遍历,这种方法写起来简单,但是效率并不是很高,这里给出三种实现Fibonacci数列的方法,分别是:递归法,闭包递归法,递推法。
递归法
var count;
var count=0;
var fib=function(n){
count++;
if(n==1||n==2){
return 1;
}
else{
return fib(n-2)+fib(n-1);
}
}
如上代码所示,递归法是最简单的解决方案,这里定义了一个count变量,是为了比较三种方法的执行效率。
闭包递推法
闭包递推法就是利用闭包的原理,将一个数组(初始为【1,1】的Fibonacci数列),存在两个函数中间,并通过内部函数不断的调用的数组,使数组以全局变量的形式存储在内存中,这样不断扩展这个Fibonacci数列,最终求得所要的Fibonacci数,下面是代码示例:
var count2=0;
var fiba = (function(){
var arr = [0,1,1]; //第0位只是占位,从第一位开始算起
return function(n){
count2++;
var res=arr[n]; /*因为内部引用了arr,并返回,导致arr一直在内存中*/
if(res){
return res;
}else{
arr[n]=fiba(n-1)+fiba(n-2);
return arr[n];
}
}
})();
虽然这里也是使用了递归,但是闭包大大减少了递归的次数,因为它是最先递归到fiba(3),就可以将fiba(3)存储到数组中,这样就可以根据数组中arr[3]+arr[2],得到fiba(4)的值,并存储在数组中,如此往复,便会得到最终结果。可以说,这是典型的用空间换时间的例子。
递推法
要说递推法是效率最高的,它在一个for循环里不断地改变fiba(n-1)和fiba(n-2)的值,从而求得最终结果,代码如下:
var count3 = 0;
var fib3 = function (n) {
var x = 1;
var y = 1;
var z = 0;
if (n == 1 || n == 2) {
return 1;
} else {
for (var i = 2; i < n; i++) {
count3++;
z = x + y;
x = y;
y = z;
}
return z;
}
};
这个方法应该也比较好理解,这里不做过多解释,下面是调用过程,并且给出了在同种情况下,它们各自count的值。
调用三种方法
onload=function(){ var t = fib(8); alert(t); //结果21 alert(count); //count=41 var z=fiba (8); alert(z); //结果21 alert(count2); //count2=13 var m = fib3(8); alert(m); //结果21 alert(count3); //count3=6 }
从上面的实例可以看出,递推法的效率最高,其次是闭包,而递归法效率最低。闭包效率虽然相对递归法高了不少,但是这种方法,如果使用不当会造成内存泄露,如果我们要求一个很大的Fibonacci数,就会导致arr数组的所占的空间越来越大,而系统又因为它不断的被引用而无法释放内存,则会导致内存泄露。所以在使用闭包的时候,一定要注意这一点。