for、var、let、const中的一些问题

2019.10.23.在温习ES6中块级作用域的时候遇到了一些问题。先开个坑周末来补。
先上代码

1
2
3
4
5
6
7
8
9
10
var inputArr = []
for(var i = 0; i < 5;i++) {
inputArr[i] = function() { // 把数组的每项都赋值成一个匿名函数
console.log(i)
}
}
// 以下几个都输出5
inputArr[0]() // 调用第1个数组里的匿名函数
inputArr[1]()
inputArr[2]()

导致这个原因是for的()括号内相当于父作用域,{}内表示子作用域。又因为var没有块级作用域每次for循环都都相当于给i重新赋值。然后在调用数组里的匿名函数的时候会找i的值,这时候因为已经循环完了,所以i的是5。如果想输出0-4一般有两种解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1.自执行函数方式
var inputArr = []
for(var i = 0; i < 5;i++) {
inputArr[i] = (function() { // 把数组的每项都赋值成一个匿名函数
console.log(i)
})()
}
// 2.用let
var inputArr = []
for(let i = 0; i < 5;i++) {
inputArr[i] = (function() { // 把数组的每项都赋值成一个匿名函数
console.log(i)
})()
}
inputArr[0]() // 0
inputArr[1]() // 1
inputArr[2]() // 2

这时候就出现了我不理解的地方了,为啥用了let之后每次他都记住了i的值,自执行函数还好理解一点。let不是出了这个块级作用域就被销毁了么?然后我去查了一下大佬的es6教程。

感觉没让我懂,之后我哥们又推荐我看了一篇帖子for循环中let与var的区别,看完之后有点内个味儿了。
结论:
1.在for循环中使用let的情况下,由于块级作用域的影响,导致每次迭代过程中的 i 都是独立的存在而且会被记住。

2.是由js引擎内部会记住上一轮循环得值,初始化i的时候就在上一轮的基础上进行计算,这里和var的重复赋值有点区别。
然后又在看《深入理解ES6》这本书的时候发现,我们一般for中用const是肯定会抱错的,但是要是在for in和for of中使用const却不会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 直接引用书中的例子
var funcs = [],
object = {
a:true,
b:true,
c:true
}
for(const key in object) {
funcs.push(function(){
console.log(key)
})
}
funcs.forEach(function(func){
func()
})

原因:因为每次迭代不会修改绑定,而是会创建一个新的绑定。这与const的定义不冲突。
当前使用块级绑定的最佳实践是:默认使用const,只有在确实需要改变的变量中使用let。这样可以值得不可变,便于追踪问题

感谢您的阅读。 🙏