JavaScript中的闭包

function foo()
  {
    var a = 2;
    function bar()
    {
      console.log(a);
    }
    return bar;                
  }
  var baz = foo();
  baz();           //2    

这段代码清晰地展示了闭包

函数bar()的作用域能够访问 foo()的内部作用域,然后将bar()函数本身当做一个值类型进行传递,函数foo()的返回值也就是内部的bar()函数。在执行foo()赋值给变量baz后,并调用了baz(),实际上只是通过不同的标识符调用了内部的函数bar()

闭包可以阻止被回收,bar()拥有涵盖foo()内部作用域的闭包,使得该作用域能够一直存活,以方便bar()(也可以是变量baz)在之后任何时间进行引用。

这个函数在定义时的词法作用域以外被调用。闭包使得函数可以继续访问定义时的词法作用域

要说明闭包,for循环是最常见的例子

for (var i = 1; i <=5; i++) {
    setTimeout(function time(){
      alert(i);
    },i*1000);
}           

这段代码会每隔1秒弹出6,一共弹出5次

为什么不是每隔1秒弹出12345,而是循环终止结束时的i值6。

弹出12345的话,是因为我们觉得循环中的每个迭代在运行时都会给自己捕获一个i的副本。

但是根据作用域和闭包的原理,实际是虽然循环中的五个函数是在各个迭代中分别定义的,但是他们都被封闭在一个共享的全局作用域中,因此实际上只有一个i,所有函数共享一个i的引用

想要输出1,2,3,4,5的话,循环过程中的每个迭代都需要一个闭包作用域。

可以通过两个方法解决这个问题:

1.通过立即执行函数

  for (var i = 1; i <=5; i++) {
    (function() {
      var j=i;
    setTimeout(function time(){
      alert(j);
    },j*1000);                                
  })();
}

立即执行函数会为每个迭代都生成一个新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部。

2.ES6中的let声明

let声明的变量有块级作用域,只能在作用域中访问,其他和var一样。

  for (let i = 1; i <=5; i++) 
  {
    setTimeout(function time()
    {
      alert(i);
    },i*1000);
  }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值