闭包

<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>

posted @ 2018-06-09 21:57  EthanCheung  阅读(146)  评论(0编辑  收藏  举报