闭包理解大全------相信你会更加理解闭包!!!

时间:2022-07-10 22:45:52

闭包概念:是指在JavaScript中,内部函数总是可以访问-其所在局部作用域中声明的参数和变量,即使在其所在局部作用域被销毁后,依然可以访问.

闭包函数:定义在局部作用域中的函数.

闭包本质:将闭包函数外的局部变量常驻内存. (在程序中,避免使用全局变量,推荐使用私有,封装的局部变量)

缺点:内存泄露(任何对象在你不在需要他之后仍然存在).

闭包的特性:1.函数内再嵌套函数; 2.内部函数可以引用外层的参数和变量;3.参数和变量不会被垃圾回收机制回收。

以下1,2例题 是对概念的理解,其余都是一些练习,配合下一章的匿名函数自执行,希望你对闭包会有更深的理解:

1.函数内部访问函数外部的数据
            var a = 1;           //全局变量
            function fn_01(){
                alert(a);
            }
            fn_01();     //1
          
            function fn_02(){
                var num = 10;
            }
            fn_02();
            alert(num);    //num is not defined 
            //外部想访问函数内部局部的私有变量,是不能直接访问到的
            //因为局部变量会在函数运行以后被销毁,这就用到了闭包。(闭包函数是可以访问到的)
            
2.通过闭包访问局部变量
            function fn_01(){
                var num = 3;           //变量
                return function(){    //闭包函数
                    return num;
                }
            }
            alert( fn_01()() );       //闭包函数访问局部作用域中的变量
            
            function fn_02(num){      //参数 var num 形式参数(形参):定义函数时接收数据的参数。 实际参数(实参):调用函数时传递的参数。
                return function(){        //闭包函数
                    return num;
                }
            }
            alert( fn_02(4)() );      //闭包函数访问局部作用域中的参数

3.循环里的匿名函数的取值问题
            function fn_01(){
                var arr = [];
                for(var i = 0;i < 5;i++){
                    arr[i] = function(){    //函数没有执行,没有取外面i的值,只将函数块赋值给了数组arr
                        return i;        
                    }
                }
                return arr;
            }
            alert( fn_01() );  
/*解释: 数组arr  循环5次都将function匿名函数存放在了数组中,函数并没有执行
            function(){
                return i;
            },function(){
                return i;
            },function(){
                return i;
            },function(){
                return i;
            },function(){
                return i;
            }

*/
       //自己执行
            function fn_02(){
                var arr = [];
                for(var i = 0;i < 5;i++){
                    arr[i] = (function(){
                        return i;
                    })();            //让闭包函数自执行,每次执行,都将i存放在数组arr中
                }
                return arr;
            }
            alert( fn_02() );    //arr = [0,1,2,3,4];

  //传参数
            function fn_03(){
                var arr = [];
                for(var i = 0;i<5;i++){
                    arr[i] = (function(i){
                        return i;    
                    })(i)                 //函数执行,返回循环每一次i的值,作为参数,传递给闭包函数,返回值i,传递给数组
                }
                return arr;
            }
            //alert(fn_04());
            var list = fn_04();
            for(var j = 0,len = list.length;j < len;j++){
                alert(list[j]);       //返回数组是[0,1,2,3,4]
            }
          //传参数加 闭包函数
           function fn_04(){
                var arr = [];
                for(var i = 0;i<5;i++){
                    arr[i] = (function(i){     //闭包函数
                        return function(){    //闭包函数    
                            return i;
                        };
                    })(i)              //函数执行,返回循环每一次i的值,作为参数,传递给闭包函数,返回值i,传递给数组
                }
                return arr;
                                    //此时arr数组存放的是function(){return i;}这个函数块  取值的时候,向上面的父级函数取i,这里的i传递的参数是循环变量每次的i
            }
            //alert(fn_04());
            var list = fn_04();
            for(var j = 0,len = list.length;j < len;j++){
               alert(list[j]());   
            }
           
练习题 1. fn(1)(2)(3)   使用闭包得到6
            function fn(x){
                
                return function(y){
                    
                    return function(z){
                        
                        alert(x+y+z);
                    }
                }
            }
            fn(1)(2)(3);
练习题 2.
            var name = "jack";
            var obj = {
                name: "Lisa",
                getName : function(){
                    return function(){     //闭包  
                        return this.name;
                    }
                }
            }
            alert( obj.getName()() );   
            
            var name = "jack";
            var obj = {
                name: "Lisa",
                getName :function(){
                    var that = this;        //this 指向obj
                    return function(){
                        return that.name;
                    }
                }                                                
            }
            alert( obj.getName()() );                                   
      
练习题 3.三个数的累加,要求:同时支持下面两种写法
            //sum(1)(2)(3)  使用闭包得到6
            //sum(1,2,3);
            var sum = (...a)=>{  //a表示所有的参数
                if(a.length == 3;){
                    return a[0] + a[1] + a[2];
                }else{
                    var x = a[0];
                    return function(y){
                        return function(z){
                            return x + y + z;
                        }
                    }
                }
            }
            alert( sum(1,2,3) );
            alert( sum(1)(2)(3) );
            
练习题 4.点击按钮,让按钮里面的值++

<style type="text/css">
 #btn{
       width:80px;
       height:30px;
       font-size: 16px;
 }
</style>
 <input type="button" value="0" id="btn"/>

         var oBtn = document.getElementById("btn")
         oBtn.onclick = function(){
                this.value = Number(this.value) + 1;
          }
            //闭包写法实现
            (function(){
                var i = Number(oBtn.value);
                oBtn.onclick = function(){
                    this.value = ++ i;
                }
            })() //减少全局变量 

          function fn_06(){
                var i = 0;
                return function(){
                    return ++ i;
                }
            }
            var n = fn_06();
            oBtn.onclick = function(){
                this.value = n();
            }


            //循环加计时器--闭包解决   
            for (var i=1; i<=9; i++) {
                setTimeout( function timer(){
                    console.log( i );
                },1000 );
            }

    /*解释  i = 0  ...覆盖 1,2,3,4   
              setTimeout(function(){console.log(i);},0)  //计时器,是延时操作,即使事件是0,也排在后面执行(异步)
              setTimeout(function(){console.log(i);},0)
              setTimeout(function(){console.log(i);},0)
              setTimeout(function(){console.log(i);},0)
              setTimeout(function(){console.log(i);},0)
                最后 i = 5  不执行下面了,  所以输出5个5  */

  //闭包解决
            for (var i=1; i<=9; i++) {
                (function(j){
                    setTimeout( function timer(){
                        console.log( j );
                    }, 1000 );
                })( i );
             }  

       //let 也可以解决(详解可以看前几章关于for循环中有关let的解释)

    for(let i = 0;i < 5;i ++){
                    setTimeout(function(){
                      console.log(i);
                   },0)        
             }
          /*      i=0
                setTimeout(function(){console.log(i);},0)
                i=1
                setTimeout(function(){console.log(i);},0)  .....i=2 i=3 i=4   */


这是 一道面试题,如何更改下面的代码,将a[6] 输出的结果得到6 ?
            var a=[];
            for(var i=0;i<10;i++){
                a.push(
                    function(){console.log(i)}
                );
            }
            a[6]();  //10
            
            var a=[];
            for(let i=0;i<10;i++){
                a.push(
                    function(){console.log(i)}
                );
            }
            a[6](); // 6
            
            var a=[];
            for(var i=0;i<10;i++){
                a.push(
                    function(i){
                        return function(){
                            console.log(i);
                        }
                    }(i)
                );
            }
            a[6]();  //6