美文网首页
JavaScript 闭包

JavaScript 闭包

作者: 艾伦先生 | 来源:发表于2016-11-20 21:25 被阅读133次

    闭包是什么

    闭包就是一个拥有变量和绑定了这些变量的环境的表达式(通常是一个函数),是一个有权访问其外部作用域中变量的函数。最常见的方式就是在某函数内部创建一个函数。

    • 优点
      能够读取函数内部的变量,并且让这些变量的值始终保存在内存中。使用闭包和匿名自执行函数实现模块化。
    • 缺点
      1.既然不释放内存,则必然会对内存的消耗很大,造成页面访问的性能问题
      2.闭包会改变父函数的私有属性,在你不经意的时候

    一个经典的例子

    function test(){  
     for(var i = 0; i < 10 ; i++){  
         setTimeout(function(){  
            console.log(i)  
        }, 0);  
      }  
    }  
    test();
    

    我相信大家都会瞬间给出答案:输出是个10,原因如下:

    • test()执行时会创建一个运行时期的上下文,而setTimeout内部的函数会放在for循环队列之后,等到for循环执行完之后才开始执行。
    • function(){console.log(i)}执行时首先会寻找函数内部的变量i。此时找不到i,再寻找test中的i
    • (闭包的概念:访问函数外的变量,这些变量只有等到闭包不使用才会被销毁)此时的i值已经变为了10,所以十次执行都会输出10。

    解决这个问题的方法如下

    function test(){  
        for(var i = 0; i < 10 ; i++){  
         (function(li){  
            setTimeout(function(){  
                console.log(li)  
             }, 0);  
         })(i);  
        }  
    }  
    test(); 
    

    再举一个例子

    function f1(){  
     var n=999;  
     nAdd=function(){n+=1}//定义了一个全局变量,相当于setter,方便在函数外部对函数内部的变量进行操作,不是本文要说明的重点  
     function f2(){  
      console.log(n);  
     }  
     return f2;  
    }  
    var result=f1();  
    result();   //返回内部函数f2,f2访问外部函数f1的局部变量n,999  
    nAdd();     // f1函数声明后,产生window.nAdd
    result();   // 1000,可见变量n保存在了内存中;  
    var result2 = f1();  
    result2();//999 这里的值为什么不是1000呢?带着疑问往下看
    

    一个函数,当没有依赖关系存在时,就会有被垃圾回收机制回收的可能,但是如果像上文案例f1()那样,将内部函数(f2)作为返回值赋值给一个全局变量,则会改变这种潜在的关系。这种即使离开函数作用域仍能通过引用来调用内部函数(或变量)的事实,意味着,只要存在调用内部函数的可能,JavaScript就需要保留被该内部函数引用的函数(即所谓的外部函数)

    JavaScript运行时会跟踪引用这个内部函数的所有变量,知道最后一个变量废弃,JavaScript垃圾回收机制才能释放对应的空间(将内部函数置为null)

    根据上面的论述,我们来分析一下第二个例子:

    • f1()函数的返回值是内部函数f2()并将返回值赋值给了全局变量result
    • f2()保存有f1()的的依赖关系,导致f2()始终在内存中未被清除,可以在外部访问到f1()中的变量
    • result2()执行后打印了999,而不是1000。是因为创建新的封闭环境,本质上是创建了一个新的对象,而闭包就是这个对象的实例方法

    小测试

    第一题:

    var name = "The Window";
     var object = {
      name : "My Object",
      getNameFunc : function(){
        return function(){
          return this.name;
        };
      }
    };
    alert(object.getNameFunc()());
    

    答案是:'The Window'

    这样理解 var fun = object.getNameFunc();这个返回的是一个function

    fun = function(){
        return this.name;
    }
    

    此时,fun中的this指向是window,所以this.name是The window

    这道题是典型的闭包没闭上~要么用聪明的that来解决,要么使用 真·闭包

    // 聪明的that
    var name = "The Window";
    var object = {
      name : "My Object",
      getNameFunc : function(){
        var that = this;//这里的that现在是相当于object这个对象了
        return function(){
          return that.name;//所以这里面输出的是object.name,也就是"My Object"
        };
      }
    };
    alert(object.getNameFunc()());
    
    // 真·闭包术
    var name = "The Window";
    var object = {
        name : "My Object",
        getNameFunc : (function(){
          return function(){
            return this.name;
         };
        })()
    };
    alert(object.getNameFunc()); //My Object
    

    推荐文章

    相关文章

      网友评论

          本文标题:JavaScript 闭包

          本文链接:https://www.haomeiwen.com/subject/femypttx.html