• 闭包


    <body>
    
    <button>测试1</button>
    <button>测试2</button>
    <button>测试3</button>
    <!--
    需求: 点击某个按钮, 提示"点击的是第n个按钮"
    -->
    <script type="text/javascript">
      var btns = document.getElementsByTagName('button')
      /* //有问题
      for(var i=0,length=btns.length;i<length;i++) {
        var btn = btns[i]
        btn.onclick = function () {
          alert('第'+(i+1)+'个')
        }
      }*/
    
      //解决一: 保存下标
      /*for(var i=0,length=btns.length;i<length;i++) {
        var btn = btns[i]
        btn.index = i
        btn.onclick = function () {
          alert('第'+(this.index+1)+'个')
        }
      }*/
    
      //解决办法: 利用闭包
      for(var i=0,length=btns.length;i<length;i++) {
        (function (i) {
          var btn = btns[i]
          btn.onclick = function () {
            alert(''+(i+1)+'')
          }
        })(i)
      }
    </script>
    </body>

    闭包

    // 最简单的闭包
    function A(){
        function B(){
           console.log("Hello Closure!");
        }
        return B;
    }
    var c = A();
    c();//Hello Closure!
    
    // 解释
    (1)定义了一个普通函数A
    (2)在A中定义了普通函数B
    (3)在A中返回B(确切的讲,在A中返回B的引用)
    (4)执行A(),把A的返回结果赋值给变量c
    (5)执行c()
    // javascript中的GC机制:在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收,否则这个对象一直会保存在内存中。
    // B定义在A中,因此B依赖于A,而外部变量c又引用了B,所以A间接的被c引用,也就是说,A不会被GC回收,会一直保存在内存中
    // 详细查看: https://www.mybj123.com/339.html
    // 经典题目
            for (var i = 1; i <= 5; i++) {
                    setTimeout(function timer() {
                        console.log(i);
                    }, 1000);
                }
            }
    // 输出 6 6 6 6 6
    setTimeout是异步的,需要等for循环里面的执行完成才会执行,等i=5的时候,i++,这个时候i就变成了6
    
    方法一:使用闭包
            for (var i = 1; i <= 5; i++) {
                (function(i) {
                    setTimeout(function timer() {
                        console.log(i);
                    }, 1000);
                })(i)
            }
    // 输出 1 2 3 4 5
    
    方法二:var改为let
            for (let i = 1; i <= 5; i++) {
                    setTimeout(function timer() {
                        console.log(i);
                    }, 1000);
                }
            }
    // 输出 1 2 3 4 5

    <!--
    1. 如何产生闭包?
      * 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
    2. 闭包到底是什么?
      * 使用chrome调试查看
      * 理解一: 闭包是嵌套的内部函数(绝大部分人)
      * 理解二: 包含被引用变量(函数)的对象(极少数人)
      * 注意: 闭包存在于嵌套的内部函数中
    3. 产生闭包的条件?
      * 函数嵌套
      * 内部函数引用了外部函数的数据(变量/函数)
    -->
    <script type="text/javascript">
      function fn1 () {
        var a = 3
        function fn2 () {
          console.log(a)
        }
      }
      fn1()
    </script>

    常见的闭包

    <!--
    1. 将函数作为另一个函数的返回值
    2. 将函数作为实参传递给另一个函数调用
    -->
    <script type="text/javascript">
      // 1. 将函数作为另一个函数的返回值
      function fn1() {
        var a = 2
        function fn2() {
          a++
          console.log(a)
        }
        return fn2
      }
      var f = fn1()
      f() // 3
      f() // 4
    
      // 2. 将函数作为实参传递给另一个函数调用
      function showMsgDelay(msg, time) {
        setTimeout(function () {
          console.log(msg)
        }, time)
      }
      showMsgDelay('hello', 1000)  //hello
    </script>

    闭包的作用 , 生命周期

    <!--
    1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
    2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
    
    问题:
      1. 函数执行完后, 函数内部声明的局部变量是否还存在?
      2. 在函数外部能直接访问函数内部的局部变量吗?
    -->
    <script type="text/javascript">
      function fun1() {
        var a = 3;
        function fun2() {
          a++;            //引用外部函数的变量--->产生闭包
          console.log(a);
        }
        return fun2;
      }
      var f = fun1();  //由于f引用着内部的函数-->内部函数以及闭包都没有成为垃圾对象
    
      f();  //4   //间接操作了函数内部的局部变量  
      f();  //5
    f = null   //此时闭包对象死亡
    </script>

    闭包的应用_自定义js模块

    /**
     * 自定义模块1
     */
    function coolModule() {
      //私有的数据
      var msg = 'atguigu'
      var names = ['I', 'Love', 'you']
    
      //私有的操作数据的函数
      function doSomething() {
        console.log(msg.toUpperCase())
      }
      function doOtherthing() {
        console.log(names.join(' '))
      }
    
      //向外暴露包含多个方法的对象
      return {
        doSomething: doSomething,
        doOtherthing: doOtherthing
      }
    }
    <!--
    闭包的应用2 : 定义JS模块
      * 具有特定功能的js文件
      * 将所有的数据和功能都封装在一个函数内部(私有的)
      * 只向外暴露一个包信n个方法的对象或函数
      * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
    -->
    <script type="text/javascript" src="05_coolModule.js"></script>
    <script type="text/javascript">
      var module = coolModule()
      module.doSomething()
      module.doOtherthing()
    </script>
    /**
     * 自定义模块2
     */
    (function (window) {
      //私有的数据
      var msg = 'atguigu'
      var names = ['I', 'Love', 'you']
      //操作数据的函数
      function a() {
        console.log(msg.toUpperCase())
      }
      function b() {
        console.log(names.join(' '))
      }
    
      window.coolModule2 =  {
        doSomething: a,
        doOtherthing: b
      }
    })(window)
    <!--
    闭包的应用2 : 定义JS模块
      * 具有特定功能的js文件
      * 将所有的数据和功能都封装在一个函数内部(私有的)
      * 只向外暴露一个包信n个方法的对象或函数
      * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
    -->
    <script type="text/javascript" src="05_coolModule2.js"></script>
    <script type="text/javascript">
      coolModule2.doSomething()
      coolModule2.doOtherthing()
    </script>

    闭包的缺点及解决

    <!--
    1. 缺点
      * 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
      * 容易造成内存泄露
    2. 解决
      * 能不用闭包就不用
      * 及时释放
    -->
    <script type="text/javascript">
      function fn1() {
        var a = 2;
        function fn2() {
          a++;
          console.log(a);
        }
        return fn2;
      }
      var f = fn1();
    
      f(); // 3
      f(); // 4
      f = null // 释放
    </script>

  • 相关阅读:
    五、MongoDB的索引
    四、MongoDB的查询
    各模块启动
    HBase1.2.6 javaapi查看rowkey 所在分区等信息
    HBase1.2.6 预分区后,数据不进入预定分区的一个 bug
    SparkStreaming程序设计
    SparkSQL程序设计
    Spark SQL概述
    常用RDD
    spark程序设计
  • 原文地址:https://www.cnblogs.com/zzxuan/p/9161542.html
Copyright © 2020-2023  润新知