闭包

63 阅读2分钟

闭包实例

<script>   
    function A(){         
        var x = 1;         
        return function(){            
            x++;             
            console.log(x);        
        }    
    }     
    var m1 = A();//第一次执行A函数     
    m1();//2     
    m1();//3     
    var m2 = A();//第二次执行A函数     
    m2();//2     
    m1();//4 </script>
  • 每次执行A函数时,都会生成一个A的活动变量和执行环境,执行完毕以后,A的执行环境销毁,但是活动对象由于被闭包函数引用,所以仍然保留 所以,最终剩下两个A的变量对象,因此m1和m2在操作x时,指向的是不同的数据
  • 为什么连续执行m1的时候,x的值在递增 因为m1在引用的活动对象A一直没有释放(想释放的话可以让m1=null),所以x的值一直递增
  • 定义函数m2的时候,为什么x的值重新从1开始了 因为又一次运行了A函数,生成一个新的A的活动对象,所以m2的作用域链引用的是一个新的x值
  • m1和m2里面的x为什么是相互独立,各自维持的 因为在定义m1和m2的时候,分别运行了A函数,生成了两个活动对象,所以,m1和m2的作用域链是指向不同的A的活动对象的

闭包涉及作用链的应用

  1. 解决循环输出问题
for(var i = 1; i <= 5; i ++){
  setTimeout(function timer(){
    console.log(i)
  }, 0)
}
  • 方案一:利用IIFE(立即执行函数表达式)当每次for循环时,把此时的i变量传递到定时器中
for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}
  • 方案二:给定时器传入第三个参数, 作为timer函数的第一个函数参数
for(var i=1;i<=5;i++){
  setTimeout(function timer(j){
    console.log(j)
  }, 0, i)
}
  • 方案三:使用ES6中的let
for(let i = 1; i <= 5; i++){
  setTimeout(function timer(){
    console.log(i)
  },0)
}

let使JS发生革命性的变化,让JS有函数作用域变为了块级作用域,用let后作用域链不复存在。代码的作用域以块级为单位