对于javaScript闭包,立即执行函数的用法的一些理解

时间:2023-01-29 16:15:52

最近在刷freeCodeCamp上面的题目,发现了这么一道有趣的题目,加深了我对于js中闭包和立即执行表达式的一些理解,题目如下:

给一个正整数num,返回小于或等于num的斐波纳契奇数之和。

斐波纳契数列中的前几个数字是 1、1、2、3、5 和 8,随后的每一个数字都是前两个数字之和。

例如,sumFibs(4)应该返回 5,因为斐波纳契数列中所有小于4的奇数是 1、1、3。

提示:此题不能用递归来实现斐波纳契数列。因为当num较大时,内存会溢出,推荐用数组来实现。

第一眼看到这个题目,我就对于他的提示产生了疑惑,为什么不可以用递归,用数组是怎么一回事?看了看他的推荐的资料,我才理解了提示的含义,以下是参考的资料:

1、递归

function Fib(n) { 
    return n < 2 ? n : (Fib(n - 1) + Fib(n - 2)); 
}

2、数组缓存

var IterMemoFib = function() { 
    var cache = [1, 1]; 
    return function (n) { 
        if (n >= cache.length) { 
            for (var i = cache.length; i < n ; i++ ) { 
                cache[i] = cache[i - 2] + cache[i - 1]; 
            } 
        } 
        return cache[n - 1]; 
    } 
}();

3、直接使用加法

function fib(n) { 
    if (n < 2) { 
        return 1; 
    } 
    var a = 1, b = 1; 
    for (var i = 2; i < n - 1 ;i++ ) { 
        b = a + b; 
        a = b - a; 
    } 
    return a + b; 
}

对比:

如果只使用一次运算,第三种方法速度最快;

如果多次使用,第二种方法明显优于其它两种;

在n较大的情况下不推荐使用第一种;n为10*10000的时候递归就已经报内存溢出了

参考的博客地址:http://www.cnblogs.com/meteoric_cry/archive/2010/11/29/1891241.html

 以上三种方法都可以用来计算斐波纳契数列,第一种采用的是递归的方法,第二种采用的是数组缓存的技巧,而第三种方法则最为直接的采用一步一步的加法。

但是第二种方法有着其他两种方法都难以超越的优势,即如果要多次使用的话,第二种方法会把之前运算过的结果缓存到cache数组当中,从而大大减少运算量,而且每次运算,第一和第三中方法都要从头开始运算,而第二种方法会先判断结果是否已经计算过了,并且不会从头开始计算,而是从尾部开始计算,而这便运用到了js中的闭包和立即执行函数的功能了。

 1  var IterMemoFib = function () {
 2         var cache = [1, 1];
 3 
 4         //下面返回的函数就是一个闭包,其中引用了上一层函数的局部变量cache,这会使的作为局部变量的cache数组常驻内存
 5         return function (n) {
 6 
 7             if (n >= cache.length) {
 8                 for (var i = cache.length; i < n; i++) {
 9                     cache[i] = cache[i - 2] + cache[i - 1];
10                 }
11             }
12             return cache[n - 1];
13         }
14     }();

 

等等,为什么在代码外边套了一个function() {//code here......}();呢?这是干嘛的呢?,其实完全可以这么写:

1  var cache = [1, 1];
2     function IterMemoFib(n) {
3         if (n >= cache.length) {
4             for (var i = cache.length; i < n; i++) {
5                 cache[i] = cache[i - 2] + cache[i - 1];
6             }
7         }
8         return cache[n - 1];
9     }

 

事实证明上述代码也是可以实现的,那么两种方法的区别在于什么地方呢?仔细比较两种方法可以发现,第一种方法只产生了一个全局变量IterMemoFib;然而第二种方法却产生了两个全局变量IterMemoFib和cache,这就是的第一种方法的优点所在。

以上就是我从这道题目中学到的关于闭包和立即执行函数的知识了,下面将这道题目的完整代码贴出供参考:

 1 var sumFibs = function () {
 2         var cache = [1, 1];
 3         return function (num) {
 4             if (num > cache[cache.length - 1]) {
 5                 var i = cache.length;
 6                 while (cache[i - 1] < num) {
 7                     cache[i] = cache[i - 2] + cache[i - 1];
 8                     i++;
 9                 }
10             }
11             var oddArr = cache.filter(function (value, index, arr) {
12                 if (value % 2 === 1 && value <= num) {
13                     return true;
14                 }
15             });
16             return oddArr.reduce(function (a, b) {
17                 return (a + b);
18             })
19         }
20     }();

 

由于本人水平有限,以上代码仅供参考。