为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript循环和作用域

标签:
JavaScript

JavaScript有一个特点,也许会让开发者头痛, 是与循环和作用域相关的.

举个例子:

const operations = []for (var i = 0; i < 5; i++) {
  operations.push(() => {    console.log(i)
  })
}for (const operation of operations) {
  operation()
}

它基本是循环了5次,将一个函数添加到operations数组里面。这个函数可打印出循环变量索引值i.

运行这些函数后

期望的结果应该是:

01234

但实际发生的是这样的:

55555

为什么会有这种情况? 因为使用的是var.

由于提升var变量, 上面的代码等同于

var i;const operations = []for (i = 0; i < 5; i++) {
  operations.push(() => {    console.log(i)
  })
}for (const operation of operations) {
  operation()
}

因此,在for-of循环中, i 依然是可见的, 它等于5,并且每次在函数中涉及到i ,都将使用这个值。

那么我们应该如何做让其变成我们想的这样呢?

最简单的方案是用 let 声明. 在ES2015中介绍到, 它们有很大的帮助,能避免关于使用var声明的一些奇怪问题。

简单的在循环变量时将var 变成 let ,能够很好的运行:

const operations = []for (let i = 0; i < 5; i++) {
  operations.push(() => {    console.log(i)
  })
}for (const operation of operations) {
  operation()
}

这是输出结果:

01234

这是怎么实现的呢?这是因为每次循环重复的时候,都将重新创造 i ,同时每个函数添加operations数组时,能获取它本身的i

记住你不能使用 const在这种情况下, 因为这会导致for在第二次循环时, 尝试赋新值报错。

另外一个非常普遍的解决这个问题是使用pre-ES6代码, 同时它被称作即时调用函数表达式 (IIFE).

在这种情况下,你可以包装整个函数,并将i 绑定在它上面。自这种方式,你正在创造一个能立即执行的函数,你从其返回的一个新的函数。因此我们可以稍后执行它。

const operations = []for (var i = 0; i < 5; i++) {
  operations.push(((j) => {    return () => console.log(j)
  })(i))
}for (const operation of operations) {  operation()}

译文出处:https://www.zcfy.cc/article/javascript-loops-and-scope

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消