闭包

作者: Cyuu | 来源:发表于2019-03-08 17:51 被阅读0次

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

    一、变量的作用域

    要理解闭包,必须先理解JavaScript特殊的变量作用域
    变量的作用域无非两种: 全局变量和局部变量

    JavaScript语言中,函数内部可以直接读取全局变量

    var n=999;
    
    function f1(){
      alert(n);
    }
    
    f1(); // 999
    

    另一方面,在函数外部自然无法读取函数内的局部变量。

       function f1(){
          var n=999;
       }
       alert(n); // error
    

    声明n变量是需要使用var,否则会变成全局变量

    二、如何从外部读取局部变量

    出于种种原因,有时候需要读取到函数内部的局部变量。 但是正常情况下,JavaScript不允许函数外部访问内部的局部变量,只有通过变通方法才能实现。

    function f1() {
      var n = 999;
      function f2() {
        alert(n);
      }
    }
    
    

    在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

    既然f2可以读取f1的局部变量,那么只要把f2作为返回值,就可以在f1的外部读取f1的内部变量

    function f1(){
      var n=999;
      function f2(){
        alert(n); 
      }
      return f2;
    }
    
    var result=f1();
    result(); // 999
    

    三、闭包的概念

    上一节代码中的f2函数,就是闭包。

    各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

    由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

    所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

    四、闭包的用途

    闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

    简单举例:

    1. 匿名自执行函数
    var data= {    
        table : [],    
        tree : {}    
    };    
         
    (function(dm){    
        for(var i = 0; i < dm.table.rows; i++){    
           var row = dm.table.rows[i];    
           for(var j = 0; j < row.cells; i++){    
               drawCell(i, j);    
           }    
        }    
           
    })(data);
    

    我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象

    2. 封装
    var person = function(){    
        //变量作用域为函数内部,外部无法访问    
        var name = "default";       
           
        return {    
           getName : function(){    
               return name;    
           },    
           setName : function(newName){    
               name = newName;    
           }    
        }    
    }();    
         
    print(person.name);//直接访问,结果为undefined    
    print(person.getName());    
    person.setName("abruzzi");    
    print(person.getName());    
    

    得到结果如下:

    undefined
    default
    abruzzi

    五、闭包的优缺点

    六、思考题

    如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

    代码片段一。

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

    代码片段二。

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

    相关文章

      网友评论

          本文标题:闭包

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