美文网首页我爱编程
你一定看得懂的 —— 闭包

你一定看得懂的 —— 闭包

作者: 2bc5f46e925b | 来源:发表于2018-04-17 08:56 被阅读17次

    Js 是一门完整的面向对象语言,同时也有 函数式语言特性。其中 就有 闭包和高级函数。

    听到 闭包,你会想到什么?
    闭包是什么?
    闭包的作用是什么?
    为什么要用闭包,它为我解决 什么问题?

    1. 它是js一种语言特性,它 跟 变量的作用域和垃圾      回收机制相关
    2 . 能够读取其它函数 内部变量的函数  称为闭包;
    3. 在外部读取引用函数内部变量,外部

    闭包

    它是一个很难又必须征服的概念。它的形成 与变量的作用域 以及生存周期密切相关。

    1. 变量的作用域
    变量的作用域 指的是变量的有效范围。
    在函数中声明一个变量的时候:①没有关键字 var ,这个变量就会变成 全局变量。
                                                      ②有关键字 var,就是 局部变量。只有在函数内部才能访问这个                                                       变量,函数外部 访问不到。

    var func = function ( ) {
          var a =1;    //  局部变量
          alert ( a ) ;
    }
    func ( )   //   1
    alert ( a )   //  a is not defined

    var func = function ( ) {
          a = 1 ;     // 全局变量
          alert( a ) ;
    }
    func( );  //  1
    alert( a ) //  1

    在JS中,函数可用来创造函数作用域。此时的函数像一层半透明的玻璃,在函数里面可以看到外面的变量。而在函数外面却看不到函数里的变量。
    这是因为,在函数中搜素一个变量的时候,如果该函数内并没有声明这个变量,那么此次的搜索过程 会随着代码的执行环境创建的作用域链 往外逐层搜索,直到全局对象为止。
    变量的搜索是从内到外 而非从外到内

    var a = 1 ;
    var func1 = function ( ) {
          var b = 2 ;
          var func2 = function ( ) {
                var c = 3 ;
                alert ( b) ;    //  2
                alert ( a );   //1
         }
         func2( );
         alert( c );  //  c is not defined;
    }
    func1 ( );

    2.变量的生命周期
    提到生命周期,不得不提 JS 具有的自动垃圾收集机制
    简单来说,就是 销毁掉环境中无用的变量,完成内存清理工作,从而回收它们所占用的空间。
    具体来说1:执行环境会负责管理代码执行工程中使用的内存。在编写JS时,开发人员不用再关心内存的使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理。原理很简单:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔周期性执行这一操作。
    具体来说2: 局部变量只在函数执行的过程中存在。而在这个过程中,会为局部变量在堆或栈内存上分配相应的空间,以便存储它们的值。然后在函数中使用这些变量,直至函数执行 结束。此时,局部变量就没有存在的必要了,因此释放掉它们的内存以供将来使用。
    对于全局变量来说,它的生命周期当然是永久的。对于函数内部 的局部变量来说,当退出函数时,这些变量即失去了它们的价值,它们都会随着函数调用的结束而被摧毁

    var func1 = function ( ) {
          var a = 1 ;
          a++ ;
          alert( a ) ; 
    }
    func1 ( ) ;    //  2;
    func1 ( ) ;   //   2;
    func1 ( ) ;   //   2;

    var func2 = function ( ) {
          var a = 1 ;
          return function ( ) {
                a++;
                alert( a );
          }
    }

    var f = func2 ();
    f ( ) ;    //  2
    f ( ) ;    //  3
    f ( ) ;   //   4

    执行函数func1时,每次执行都 弹 2。说明每次执行,a重新被赋值 1; 即每次调用函数结束后, 变量 a 在堆或栈里存的值被销毁(赋值null)。

    执行函数func2时,数字依次增加。说明局部变量a并没有在函数执行后被销毁。 而是存活在某个地方。这是因为当执行 var f = func2( ) 时,f 返回了一个匿名函数的引用,这个引用可以访问到 func2 () 被调用时产生的环境,而局部变量 a 一直处在这个环境里。既然 局部变量还能被外界访问,这个局部变量就有了不被销毁的理由。 

    var nodes = document.getElementsByTagName('div');
    for(var i = 0; i < nodes.length; i++) {
         nodes[i].onclick = function () {
                   alert( i )
          }
    }

    无论点击哪个div ,最后弹的都是 5.这是因为 onclick 是异步触发的,当点击某个div时,会顺着作用域链由内向外查找变量 i 值。 而for循环早已结束,每次找到的都是 5。
    解决方法是 在闭包的帮助下,把每次循环的 i 值都封闭起来。当在事件函数中顺着作用域链查找变量 i 时,会先找到封闭在闭包环境中的 i .

    for(var i = 0; i < nodes.length; i++) {
       (function(i){
             nodes[i].onclick = function () {
                   alert( i )
             }
       })(i)
    }

    相关文章

      网友评论

        本文标题:你一定看得懂的 —— 闭包

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