• 关于闭包的理解


    一、变量的作用域

    要理解闭包,首先要理解变量的作用域,在JavaScript中,变量的作用域分为两种,全局作用域以及局部作用域。JavaScript语言的特别之处就在于,函数内部可以访问函数外部的全局变量,但是函数外部无法读取函数内部的局部变量。

    二、如何从函数外部读取函数内部的局部变量?

    出于种种原因,我们有时候需要获取到函数内部的局部变量。但是,上面已经说过了,正常情况下,这是办不到的!只有通过变通的方法才能实现。那就是在函数内部,再定义一个函数。

    function a(){
        var i=0;
        function b(){
            alert(i);
        }
    }

    在上面的代码中,函数b是包含在函数a中的,那么函数a中的所有局部变量,在函数b中都是可访问的。相反,函数b中定义的局部变量,在函数a中并不可见。这就是JavaScript中的作用域链。

    子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

    既然b可以读取a中的局部变量,那么只要把b作为返回值,我们不就可以在a外部读取它的内部变量了吗!像下面这样

    function a(){
        var i=0;
        return function b(){
            alert(i);
        }
    }
    var c=a();
    c();  //会弹出0

    三、闭包的概念

    在上面的代码中,就形成了闭包,闭包是指有权访问另外一个函数作用域中的变量的函数,这个概念告诉我们两点:

    第一闭包其实是一个函数,第二这个函数可以访问其他函数作用域中的变量

    四、闭包的应用场景

    • 采用函数引用方式的setTimeout调用
    setTimeout(code,millisec)接收两个参数,第一个参数可以是一段js代码块,也可以是一个函数,第二个参数是函数延迟执行的时间,如果第一个参数我们传入的是一个函数,那么我们传入的参数实际上是函数对象的引用,
    那么这时候我们就不能像函数传参了,这个时候闭包就派上了用场。
    function fun(num){
        var age=num;
        return function(){
            console.log(age);
        }
    }
    
    var getAge=fun(200);
    setTimeout(getAge,1000);
    • 给对象设置私有变量,并且利用特权去访问私有变量
    
    
    function Fun(){
      var name = 'tom';
      
      this.getName = function (){
        return name;
      }
    }
    
    var fun = new Fun(); 
    console.log(fun.name);//输出undefined,在外部无法直接访问name
    console.log(fun.getName());//可以通过特定方法去访问
    • 封装相关功能集

    一个内联执行的函数表达式返回了内部函数对象的一个引用。并且分配了一个全局变量,让它可以被作为一个全局函数来调用。而缓冲数组作为一个局部变量被定义在外部函数表达式中。它没有被扩展到全局命名空间中,并且无论函数什么时候使用它都不需要被再次创建。

    var getImgInPositionedDivHtml = (function () {
       var buffAr = [
         '<div id="',
         '',   //index 1, DIV ID attribute  
         '" style="position:absolute;top:',
         '',   //index 3, DIV top position  
         'px;left:',
         '',   //index 5, DIV left position  
         'px;',
         '',   //index 7, DIV width  
         'px;height:',
         '',   //index 9, DIV height  
         'px;overflow:hidden;"><img src="',
         '',   //index 11, IMG URL  
         '" width="',
         '',   //index 13, IMG width  
         '" height="',
         '',   //index 15, IMG height  
         '" alt="',
         '',   //index 17, IMG alt text  
         '"></div>'
       ];
       return (function (url, id, width, height, top, left, altText) {
         buffAr[1] = id;
         buffAr[3] = top;
         buffAr[5] = left;
         buffAr[13] = (buffAr[7] = width);
         buffAr[15] = (buffAr[9] = height);
         buffAr[11] = url;
         buffAr[17] = altText;
         return buffAr.join('');
       });
     })();

    五、闭包所引发的问题

    • 内存泄漏

    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    • this的问题

    this对象是在运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数作为某个对象的方法调用时,this等于那个对象。不过匿名函数的执行环境具有全局性,因此其this对象通常指向window。但有时候,由于编写闭包的方式不同,这一点可能不会那么明显。也就是说使用闭包,有可能会意外改变this的值。

    所以在实际场景中,我们一定要谨慎使用闭包。

  • 相关阅读:
    android 服务与多线程
    “产品级敏捷” 的这条路; 逐步的形成一高效的产品开发生态系统
    hdoj 1116 Play on Words 【并查集】+【欧拉路】
    辛星跟您玩转vim第四节之操作文本内容
    UVa 10828 Back to Kernighan-Ritchie 高斯消元+概率DP
    CMMI过程改进反例
    UVA 11077
    Yii 框架 URL路径简化
    交水费一波四折
    雷观(十五):提高生产力和程序员价值的2种方法
  • 原文地址:https://www.cnblogs.com/xuxiaozhi/p/10455163.html
Copyright © 2020-2023  润新知