• JS闭包


    什么是闭包?

      javascript和其他编程语言一样,也采用词法作用域,也就是说,函数的执行依赖于变量作用域.js函数对象的内部状态不仅包含函数的代密码逻辑,还必须引用当前的作用域。

      函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。

      这就是一个闭包,它可以在外部通过某一种手段(方法)可以访问到内部的变量:

    <script type="text/javascript">
                function fun1(){
                    var a = 100;
                    function fun2(){
                        console.log(a);
                    }
                    return fun2;
                }
    
                var fun = fun1();
                fun()
    </script>

     

    闭包的特点:

      1)占内存:当内部的函数被保存到了外面,就会形成闭包,闭包导致原有的函数执行完成了以后作用域链不会得到释放

    造成了内存的泄露

      2)保护私有变量的安全

     

    闭包的应用:

      1)计数器:

        由于每次访问的都是同一个作用域,在函数掉用完一次之后并没有被回,反而更新了它的作用域,所以函数每调用一次,它的值就会更新,次数就会增加一次。

    function add(){
               var num = 0;
               return function(){
                  num++;
                 console.log(num)
                }
      }
      var fun = add();
      fun()              //1
      fun()              //2

      

      2)做缓存结构  

        每调用一次jia函数它就会加一,每调用一次jian函数它就会减一,

    function fun(){
      var num = 0;
      function jia(){
           num++;
       console.log(num);
       }
      function jian(){
          num--;
        console.log(num)
       }
        return [jia,jian];
    }
    var jia = fun()[0];
    var jian = fun()[1];
    jia()          //1
    jian()         //-1
    jia()          //2
    jian()         //-2
     

        

       3)封装

     

    实例

     利用闭包,解决循环添加事件遇到的作用域问题:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <ul>
                <li>0</li>
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
                <li>5</li>
                <li>6</li>
                <li>7</li>
                <li>8</li>
                <li>9</li>
            </ul>
            <script type="text/javascript">
                var lis = document.getElementsByTagName("li");
                for(var i = 0;i < lis.length;i++){
                    lis[i].onclick = function(){
                        console.log(i)
                    }
                    /*(function(i){  
                        lis[i].onclick = function(){
                            console.log(i)
                        }
                    })(i)*/
                }

        </script>
      </body>
    </html>

     

      如上代码,获取li元素,然后为每个li循环添加一个单击事件,使单击同的li显示对应的类数组的索引。

      但实际上,却是这种情况:(如图)

       单击不同的li,控制台显示的都是10。

      这是因为,函数作用域的问题:

      1)先生成一个GO

      2)预编译时

    GO = {
      lis : undefined
      i : undefined
       }
    3)执行后
    GO = {
      lis : {}
      i : 10
    }

    4)函数调用后生成10个AO
       lis[i].AO(i = 0-9){  *10

    }

       此时在lis[i]函数中并没有找到i,所以只能向上级寻找,所以找到上级的i为10。这也就是每次单击时输出都为10的原因了。

      现在我们用闭包来解决这个问题,把上面的那种方式注释,将其放到一个立即执行函数中,就形成了一个闭包。

    <script type="text/javascript">
                var lis = document.getElementsByTagName("li");
                for(var i = 0;i < lis.length;i++){
    //                lis[i].onclick = function(){
    //                    console.log(i)
    //                }
                    (function(i){   //ec6之前解决的方法,有且只有这一种
                        lis[i].onclick = function(){
                            console.log(i)
                        }
                    })(i)
                }
    </scrip>

    此时我们单击时就可以获取正确的索引值。

      此时的生成的GO是同之前的GO 相同的,只是在执行立即函数时分别生成了10个AO,

     {

        i : 0 - 9
       }

      当再次触发单击事件时,单击函数寻找的对象就成了父级的AO的i,即立即执行函数的10个AO中的i。所以单击第i个就会寻找到与之对应的i的值,也就是不同li的索引值。

  • 相关阅读:
    为什么单个TCP连接很难占满带宽
    上传NUnit的单元测试结果和OpenCover的单元测试覆盖率到SonarQube服务中
    使用Visual Studio Code Coverage和nunit上传单元测试覆盖率和单元测试结果到SonarQube上
    java安装1.8的经验和Error: Registry key 'SoftwareJavaSoftJava Runtime Environment'CurrentVers问题处理
    NSubstitute.Analyzers检测NSubstitute用法冲突
    在TeamCity中执行gtest单元测试
    iOS OpenGL ES入门
    iOS 基础知识
    【内推】字节跳动-头条小说&番茄小说
    iOS开发小记(十四)
  • 原文地址:https://www.cnblogs.com/1234wu/p/10139919.html
Copyright © 2020-2023  润新知