闭包

93 阅读2分钟

闭包的概念

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。函数和函数内部能访问到的变量也叫环境的总和,组成一个闭包。

闭包的作用

  1. 可以读取函数内部的变量。

  2. 一个就是让这些变量的值始终保持在内存中。

    function foo() {
        var a = 2;
        return function fun1() {
            console.log(a)
        }
    }
    var fun2 = foo()
    fun2()  //2
    

    在上面的例子中,fun1 能够访问 foo 的内部作用域。在 foo()执行后,把 foo()的返回值 fun1 赋值给 fun2 并调用 fun2。打印出了结果 2 。

    此时,我们可以说 fun1 记住并访问了所在的词法作用域 或者说 fun2 访问了另一个函数作用域中的变量。

    由于引擎有自动的垃圾回收机制,在 foo()执行后(不再使用),通常 foo 的整个内部作用域会被销毁,对内存进行回收。闭包的神奇之处正是可以阻止这件事情的发生,因为 fun1 依然持有对该作用域的引用,这个引用就叫做闭包。

  3. 闭包可以用来隐藏一个变量,比如有一个变量,我们不想别人直接访问它,而是间接使用你提供的方法来操作它,就可以使用闭包。

    function outerFn(){
     var i = 10;
     window.add = function(){
          i+=1;
    
     }
     return i
    }
    var inner = outerFn();
    inner(); //10
    add();
    inner(); //11
    

使用闭包的注意点

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

  2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    let add = null
    function f1(){
     var n=999;
     add=function(){
         n+=1;
     }
     function f2(){
        return n;
     }
     return f2;
    }
    
     var result=f1();
     result(); // 999
     Add();
     result(); // 1000
    

    此时 add 方法是一个公有方法,可以直接操作,改变 n 的值,应当注意这一点。