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
运行这些函数后,期望的结果应该是:
0
1
2
3
4
但实际发生的是这样的:
5
5
5
5
5
为什么会有这种情况? 因为使用的是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()
}
这是输出结果:
0
1
2
3
4
这是怎么实现的呢?这是因为每次循环重复的时候,都将重新创造 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()
}
原文链接: flaviocopes.com
译文出处:https://www.zcfy.cc/article/javascript-loops-and-scope
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!