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


    最近在刷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     }();

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

  • 相关阅读:
    机器人对话小程序
    partial关键字的含义
    TreeView控件常用写法
    电话本管理程序(实现增删改查功能)
    三层架构
    c# RegistryKey 的相关简单操作
    VS2010程序打包操作(超详细的)
    一些中文.net讲座
    对象表单自动数据邦定
    AspNetForums 2.0中的全文检索
  • 原文地址:https://www.cnblogs.com/txwslyf/p/6807846.html
Copyright © 2020-2023  润新知