求解这两个输出区别?

const Greeters = []
for (var i = 0 ; i < 10 ; i++) {
  Greeters.push(function () { return console.log(i) })
}
Greeters[0]() // 10
Greeters[1]() // 10
Greeters[2]() // 10
const Greeters = []
for (let i = 0 ; i < 10 ; i++) {
  Greeters.push(function () { return console.log(i) })
}
Greeters[0]() // 0
Greeters[1]() // 1
Greeters[2]() // 2

第二个用let后面不应该是undefined吗。。
还有为什么Greeters数组里保存的是[function () { return console.log(i)},function () { return console.log(i)},...,function () { return console.log(i)}]而不是
[function () { return console.log(0)},function () { return console.log(1)},...,function () { return console.log(9)}]?

阅读 2.1k
2 个回答

典型面试题,变量生命周期问题,for循环问题和函数形参问题。
let和var的不同,var是在当前代码块结束之后仍然在内存保留该变量和值,而let则是不保留,直接回收。
而for循环输出是等到循环全部结束。
所以第一种全部都是10。
而第二种方式不是undefined呢,很简单,用到了闭包,注意这里返回的不是值,而是函数,如果第二种直接输出,那就是undefined,但是现在返回函数,我们还记得函数的形参吗,没错,函数调用时形参是对实参的一个复制,所以在输出时实参虽然被回收了,但是形参还保留了值。所以JS中循环取值和输出的最简单解决方式就是闭包。

第一种情况,我觉得相当于这样:

var i;
function print() {
    return console.log(i);
}
const Greeters = []
for (i = 0 ; i < 10 ; i++) {
  Greeters.push(print);
}
console.log(`Now i=${i}`);// 注意这里i = 10;
Greeters[0]() // 10
Greeters[1]() // 10
Greeters[2]() // 10

第二组情况,let 活动范围仅限于for循环中,那么每次把函数加入到数组中时,i传递了当前的i值,

function () { 
    return console.log(i);
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
1 篇内容引用
推荐问题