for (var i = 3; i < 4; i++) {
data[i] = function () {
console.log(i);
};
}
data[3]()// 打印结果为 4;
// console.log(data[3]());
输出是4,但是为什么不是输出3呢,所以console.log里面的i是怎么变成4的呢,for循环里面的i最大不就是3吗
for (var i = 3; i < 4; i++) {
data[i] = function () {
console.log(i);
};
}
data[3]()// 打印结果为 4;
// console.log(data[3]());
输出是4,但是为什么不是输出3呢,所以console.log里面的i是怎么变成4的呢,for循环里面的i最大不就是3吗
打印的 i
来自于全局作用域。
要彻底理解这个问题,需要理清两个知识点。
网上关于这两者的介绍有很多,可以搜索一下仔细看看。
改成这样呢?
var data = [];
for (var i = 3; i < 4; i++) {
data[i] = i;
}
console.log(data[3])
当前的 i 是一个全局变量,循环的本质是到条件不满足才会结束 i=3 时仍然符合条件,进入了循环,这时又执行了 i++ 变成了 4,4 不符合条件,所以不再进入循环,i 停留在了 4 上。所以这里 console.log(i) 都会是 4。那为什么中间的量没有保存呢,是因为这里中间的变量没有形成闭包,稍微修改
,用 IIFE 形成一个闭包,就可以输出 3 了。
for (var i = 0; i < 4; i++) {
data[i] = (function(j) {return function() { console.log(j) }})(i)
}
console.log(data[3]()); // 输出 3
//没有块作用域
if(true){
var color='red'
}
console.log(color) //"red"
// i=3 会执行,再继续i++ 后,i<4 不成立,因为此时的i=4
for (var i = 3; i < 4; i++)
为什么没人提到let
呢,全都在说循环退出时i的值,只有一个人提到了作用域。不过我一直没有特别注意作用域或闭包的问题,也一直用得好好的。如果你把var
改成let
,输出就会是3
了。如果是var
的话,通过这个循环往data
里放的4个函数所打印的i
是同一个i
,也就是你在for
循环初始化循环变量时声明那一个的i
。你可以尝试以下代码:
for(let i = 0; i < 4; i++) console.log(i)
console.log(i) // ReferenceError: i is not defined
for(var i = 0; i < 4; i++) console.log(i)
console.log(i) // 4
8 回答4.6k 阅读✓ 已解决
6 回答3.3k 阅读✓ 已解决
5 回答2.8k 阅读✓ 已解决
5 回答6.3k 阅读✓ 已解决
4 回答2.2k 阅读✓ 已解决
4 回答2.8k 阅读✓ 已解决
3 回答2.4k 阅读✓ 已解决
通俗点讲,
data
这个数组,在for
循环中被添加了一个元素(因为i
初始值为3
,并且< 4
,所以只会执行循环体一次),这个元素是一个function
。相信这一点,题主是明白的。而且,因为
i == 3
,所以,这个元素的实际索引是3
,也就是data[3]
是一个function
。i
初始为3
,且该循环体执行了一次。要知道,循环体执行结束后,会执行一次i++
,然后才会去判断i < 4
是否成立。也就是说,此时i
已经等于4
了。这样的话,答案已经比较明显了:此时执行data[3]()
,输出的i
自然也就是4
了。PS:
data[3]()
输出是4
,但是,console.log(data[3]())
会输出undefined
。因为data[3]
这个function
并没有return
任何值。