zoukankan      html  css  js  c++  java
  • 分分钟搞懂JS-闭包函数

     1 //抛开概念!直接上代码,看实例
     2 
     3 var i=100;
     4 function add1(){
     5    alert(i); 
     6    i++;
     7 }
     8 function add2(){
     9    var j=100;
    10    alert(j); 
    11    j++; 
    12 }
    13 
    14 //测试;
    15 
    16 //    add1(); //100
    17 //    add1(); //101
    18 //    add1(); //102
    19 //    
    20 //    add2(); //100
    21 //    add2(); //100
    22 //    add2(); //100
    23 
    24 /*为什么呢 原因很简单
    25 i 是全局变量,只有页面关闭的时候,才会被GC回收;
    26 j 是局部变量,函数执行完毕后就 被GC 回收;
    27 
    28 问:有没有办法将j 变成"全局变量"呢?
    29 A同学答:有,将j写在外面(尼玛,傻逼啊)
    30 B同学答,用return(有点接近了) 然后用全句变量来接收;
    31 C同学答:闭包(完美)    
    32 */
    33 function add3(){
    34   var j=100;
    35   function fun(){
    36    alert(j);
    37    j++;
    38   }
    39    return fun; //注意这里;
    40 }
    41 
    42 /*
    43 测试:
    44 
    45 var obj=add3(); //执行add3()函数,同时返回了fun的引用(也就是fun的函数体)
    46 
    47 //直接alert(obj) 你会看到他的函数体- function fun(){....} 再加上一个括号(),就可以执行了
    48 
    49    obj(); //100
    50 
    51    obj(); //101
    52 
    53    obj();//102
    54 
    55  */

    当函数a的内部函数b 被函数a 外的一个变量引用的时候,就创建了一个闭包。

    简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。

    那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收

    最后,如果你能看懂这段代码你就理解了闭包!

     1    var name="window";
     2    var object={
     3      name:"my object",
     4      getName:function (){
     5          return function (){
     6              return this.name; 
     7          }
     8      }
     9       
    10   }
    11  alert(object.getName()()); //window

    闭包的多种写法:

    写法一:

      function f1(){
         var index=1;
         function f2(){
            alert(index);
            index++; 
         }
         return f2;
      }
      //调用
      var test=f1();
      test(); //1
      test(); //2
      test(); //3

    写法二:

      function outer(){
          var index=1;
         return function(){ //使用匿名函数
             alert(index);
             index++;
         }
      }
     var bibao=outer();
      bibao();
      bibao();
      bibao();

    写法三: 

    var outer=(function (){
          var index=1;
          return function (){
             alert(index);
             index++;  
          }
        
    })();
    
    outer();
    outer();
    outer();

    写法四:

    var outer=null;
    (function (){
        var index=1;
        function inner(){
          alert(index++);    
        };
        outer=inner;
    })();
    outer();
    outer();
    outer();

    总之就是函数之间的嵌套,变量之间的互相引用;

    javascript的垃圾回收原理

    (1)、在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收; 
    (2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。

     总结:

    实例:

    html代码:

              <ul>
                        <li>123</li>
                        <li>456</li>
                        <li>789</li>
                        <li>010</li>
                </ul>

     js代码:(错误方式) 

    window.onload = function(){
                var lis = document.getElementsByTagName('li');
                var len=lis.length;
                for (var i=0;i<len;i++){
                        lis[i].onclick = function(){        //当点击时for循环已经结束
                        alert(i);
                        };
                }
        }

    js代码:(错误方式)

    window.onload=function (){
         var index=0;
         var lis=document.getElementsByTagName("li");
         var len=lis.length;
         for(var i=0;i<len;i++){
             lis[i].onclick=function (){
                alert(index);  //这样做,避免了i直接等于3,但是,却没有绑定到指定的对象上滴呀
                index++;
                if(index==len){
                    index=0;
                }
             }
         }
    }

    js代码:(改进方式一)面向对象+this关键字的使用

    window.onload=function (){
      var lis=document.getElementsByTagName("li");
      var len=lis.length;
      for(var i=0;i<len;i++){
          lis[i].index=i; //给每个变量动态的绑定一个属性,并赋值
          lis[i].onclick=function (){
              var temp=this.index; //然后使用this关键字;
              alert(temp);  
          }
      }
    }

    js代码改进二:让i独立出来,index作为他的一个“副本”! i的变化不再影响到我们index

    function showInfo(obj,index){
       obj.onclick=function (){
         alert(index);   
       }
    }
    
    window.onload=function (){
      var lis=document.getElementsByTagName("li");
      var len=lis.length;
      for(var i=0;i<len;i++){
         showInfo(lis[i],i);//i的改变和 index无关滴呀  
      }
    }

    原理解析一:

       var index=1;
       
       function change1(){
         index=index+1;
       }
       
       function change2(){
        index=index+2;
       }
       change1();
       change2();
       alert(index); //4

    原理解析二:

       function change1(val){
         var temp=val;
         temp=temp+1;
       }
       
       function change2(val){
         var temp=val;
         temp=temp+2;
       }
       
       change1(index);
       change2(index);
       alert(index);
       //这样这不会改变;

    最总版本:(关键-传递副本)

     var index=1;
      (function (val){
         val=100;  
      })(index);
       
      (function (val){
         val=10000;  
      })(index);
       
       alert(index);

    js代码:(闭包实现)模块化代码,减少全局变量的污染-最好的方式;

    我们需要在每次循环时为变量 i 值创建一个拷贝,重点在:模块话代码,形成一个独立的区域;

    window.onload=function (){
         var lis=document.getElementsByTagName("li");
         var len=lis.length;
         for(var i=0;i<len;i++){
             (function (e){
                  lis[e].onclick=function (){
                     alert(e);  
                  }
             })(i); //形成一个独立的区域互补干扰
         }
    }

    继续扩展,这段代码是不是闭包?还是仅仅是一个你们匿名函数的自执行呢? 

             (function (e){
                  lis[e].onclick=function (){
                     alert(e);  
                  }
             })(i)
     //闭包概念:闭包是指某种程序语言中的代码块允许一级函数存在并且
      //在一级函数中所定义的自由变量不能被释放,直到一级函数释放前,
      //一级函数外也能应用这些未释放的自由变量;
     var shit=function (y){
        var x=y;
        return function (){
          alert(x++); //这里调用了一级函数的局部变量x
          //上下连个交换着尝试
          alert(y--); //这里调用参数变量,是自变量;    
        }}(5);
        
    shit();  // 5 5
    shit();  // 6 4
    shit();  // 7 3

    关于内存泄露的问题;

    function closure(){
       var div=document.getElementById("div1");//div用完之后一直驻留在内存中
       div.onclick=function (){
          alert(div.innerHTML);  //这里导致了内存泄露得呀
          //长期扎住在内存中得,没有得到是释放;   
       }
    }
    
    //优化:
    function closure2(){
      var div=document.getElementById("div1");
      var text=div.innerHTML;
       div.onclick=function (){
          alert(text);  //这里导致了内存泄露得呀
          //长期扎住在内存中得,没有得到是释放;   
       }
       div=null;
    }

    再推荐一篇关于闭包的好文章

    http://segmentfault.com/a/1190000000652891

    应用

    看我另外一篇文章:

    js 动画实现原理,就是闭包的一个典型应用的呀;

     

     

     

     

     

     

  • 相关阅读:
    .net的Timer
    WPF笔记(9)模板(Template)
    WPF笔记(6)数据绑定(DataBinding)
    WPF笔记(8)样式(Styles)
    WPF笔记(7)资源(Resources)
    程序无法退出调试
    WPF笔记(1)XAML和code概述
    ASP.NET程序中常用编程代码(1)
    在ASP.NET中防止注入攻击
    ASP.NET程序中常用编程代码(2)
  • 原文地址:https://www.cnblogs.com/mc67/p/4803006.html
Copyright © 2011-2022 走看看