Bootstrap

前端学习——04——js闭包

可参考03——作用域的内容

小例子:

demo执行就是b执行,只是不同名字,a里return b语句并没有执行b函数

 b定义时就保存了a的劳动成果,b执行完后回到定义的状态并且销毁了自己的AO(这里是空),不销毁别人的AO,所以第二次执行是102

 内存泄漏就是占有内存的意思

 

函数声明:function test(){} 函数声明没有被执行

函数表达式:函数表达式能被执行,var demo=function(){}() 变成一次性的了,再去控制台查看demo显示为空的demo变量,执行完函数就销毁了 ,

立即执行函数

<!DOCTYPE html>
<html lang="en">
<head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <!-- 
            闭包:当内部函数被保存到外部时,将会生成闭包,闭包会导致原有作用域链不释放,造成内存泄露(占用)
            闭包的作用:
                1:函数累加器
                2:可以做缓存(存储结构)
                3:可以实现封装,属性私有化
                4:模块化开发,防止污染全局变量
       -->
   <!-- 立即执行函数:定义 此类函数没有声明,在一次执行过后即释放,适合做初始化工作
         针对初始化功能的函数,执行完就被销毁掉,不占用空间,它有一般函数的特点,不同的是执行完会被销毁         
         (function (){}()); W3C建议第一种
         (function (){})();
         执行函数后,在控制台输入函数名,会显示 ***is not defined
         
-->
          <script>
          (function abc(){//可以是匿名函数 function (){}())
           var a=123;
           var b=234;
           console.log(a+b);
        }())//后面有个小括号,小括号是执行括号, 执行完就找不到了
          </script>

          <!-- 括号里也可以写形参 后面的小括号传实参 -->
          <script>
               (function (a,b,c){
                 console.log(a+b+c*2);
                }(1,2,3))
          </script>

      <!-- 可以有返回值 -->
          <script>
         var num=(function (a,b,c){
                  var d=a+b+c;
                  return d;
            }(1,2,3))
          </script>
       <!-- *只有表达式才能被执行符号执行
       函数声明:function test(){}
       表达式:test()
       函数表达式:var test=function(){
             console.log('a');
       }()
      可执行表达式被执行后,放弃函数名字,和执行函数一样,执行一次就被放弃了-->
       <script>
      function test(){
              console.log('a');
        }//() 这里不可以执行 语法错误
       test();//表达式可以执行
       var testSecond=function (){
             console.log('b');
       }();//可以执行,也是表达式  这种写法和立即执行函数一样,执行一次以后就被放弃了
       </script>


        <!-- 函数声明加+(正)-(负) !(感叹号)会变成表达式,所以加括号可以执行了,所以立即执行函数   (function (){})()也可以执行,因为外面加了括号也变为表达式了。  乘除不可以 等也可以变成立即执行函数 -->
       <script>
           +function testA(){
                 console.log("aa");
           }();
       </script>
           


    <!--函数累加器 -->
       <script>  
      function add(){
            var count=0;
            function demo(){
                  count++;
                  console.log(count);
            }
            return demo;
      }     
      var counter=add();
      counter();//1
      counter();//2
      counter();//3
      counter();//4
      counter();//5
      counter();//6
       </script>
     <!-- 可以做缓存例1 -->
       <script>
             function test(){
                 //a和b拿的都是test的AO  共用test的AO,是同一个AO
                   var num=100;
                   function a(){
                         num++;
                         console.log(num);
                 } 
                 // a被定义 a.[[scope]] 0:testAO
                 //                     1:GO 
                 function b(){
                       num--;
                       console.log(num);
                 }
                 //b 被定义 b.[[scope]] 0:testAO
                 //                     1:GO
                 return [a,b];
             }
             var myArr=test();
             myArr[0]();//101
             //a doing a.[[scope]]  0:aAO
             //                     1:testAO
             //                     2:GO
             myArr[1](); //100 
              //b doing b.[[scope]] 0:bAO
             //                     1:testAO a执行后改变的AO num=101
             //                     2:GO

              </script>
          <!-- 可以做缓存例2 -->
                <script>
                  function eater(){
                        var food="";//相当于一个隐式存储结构
                        var obj={
                              eat:function(){
                                    console.log("i am eating " +food);
                                    food="";
                              },
                              push:function(myFood){
                                    food=myFood;
                              }
                        }
                        return obj;
                  }
                  var eater1=eater();
                   eater1.push('banana');
                   eater1.eat();
                </script>

                <!-- 可以做缓存例2 -->
                <script>
                function test(){
                      var food="apple";
                      function a(){
                            food="banana"
                      }
                      function b(){
                            console.log(food);
                      }
                }

                </script>


                <!-- 编程时要看逻辑,不能被视觉所欺骗了 -->
                  <!-- 一个我似懂非懂的问题 -->
                <script>
                function test(){
                      var arr=[];
                      for(var i=0;i<10;i++){
//arr[i]是执行语句,function是定义语句,并没有执行,函数在定义时是不执行的,里面的document根本不看,执行时才看函数里的内容,定义时根本不看里面是什么
                            arr[i]=function(){
                                  document.write(i);
                            }
                      }
                      return arr;//for循环后,这一步保存出去,i=10,且这10个函数共用一个AO
                }
                var myArr=test();
                for(var j=0;j<10;j++){
                      myArr[j]();//这里才执行 并在AO上找到变量i
                }//输出10个10  因为第一个for循环结束以后,才调用的函数,在外部执行,i=10了
                </script>
                <!-- 一个简单的例子使我懂上面那个问题 -->
                <script>
                      var num=100;
                function test(){
                      console.log(num);
                }
                num=200;
                test();//200  虽然在上面定义的,但是在下面才执行,执行时再去拿那个值
                </script>


               <!-- 修改后的之前那个问题,能输出0-9 -->
                <script>
                        function test(){
                              var arr=[];
                              for(var i=0;i<10;i++){
//立即执行函数放到循环里就是10个立即执行函数
                              (function (j){
              //立即执行函数是读到了就执行 在for循环里就执行,但是arr[j]相等的function在myArr()才会执行  
                              arr[j]=function (){
                                    console.log(j);
                              }
                         }(i)) 
                              }
                         
                             return arr;
                        }
                        var myArr=test();
                        for(var j=0;j<10;j++){
                              myArr[j]();
                        }
               </script>

            

                
</head>
<body> 
      
</body>
</html>

 

 被保存到外部的函数拿到的是对应的立即执行函数的劳动成果,一共产生了10个独一无二的立即执行函数,立即执行函数也是函数,也会有执行器上下文,立即执行函数执行完只是引用消失,

 <script>
  /*没有return也可产生闭包 只要一个函数嵌套另一个函数,里面的那个函数保存到外部去了,并且一直保存着外面那个函数
  执行期上下文*/
var obj={}
function a(){
  var aa=132;
  function b(){
    console.log(aa);
  }
  obj.fun=b
}
a()
obj.fun()
  </script>

立即执行函数:执行完一次就被销毁,立即执行函数也会经历预编译,有执行器上下文

let也可以解决闭包

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      div {
        width: 100px;
        height: 100px;
        background-color: darkcyan;
      }
    </style>
  </head>
  <body>
    <script>
           function test(){
                            var arr=[];
                            for(let i=0;i<10;i++){
      //arr[i]是执行语句,function是定义语句,并没有执行,函数在定义时是不执行的,里面的document根本不看,执行时才看函数里的内容,定义时根本不看里面是什么
                                  arr[i]=function(){
                                        document.write(i);
                                  }
                            }
                            return arr;//for循环后,这一步保存出去,i=10,且这10个函数共用一个AO
                      }
                      var myArr=test();
                      for(var j=0;j<10;j++){
                            myArr[j]();
                      }
    </script>
  </body>
</html>

因为{}是块级作用域。let只在当前的块级作用域内有效,下次在循环的时候,相当于又一个作用域,这次循环的i的值,在这个作用域内有效。

所以会找对应的块级作用域中的i。

;