for 循环中的 let 声明和 var 声明

我们知道,ES6 之后,出现了 let 关键字。至此,块级作用域势如破竹,占据一席之地。

今天就好好聊一聊,块级作用域范畴中,for 循环里面 let 声明和 var 声明,有啥区别?

最基本的场景:

在 let 未出现之前,for 循环中的迭代变量会泄露到循环体之外。

for(var i = 0; i < 5; i++) {
  // 循环体
}
console.log(i); // 5

出现 let 之后,这个问题就消失了,因为迭代变量的作用域只限于循环体内。

for(let i = 0; i < 5; i++) {
  // 循环体
}
console.log(i); // ReferenceError: i is not defined

还有一个面试中经常提及的问题,在 for 循环的循环体内定义一个定时器,循环结束后,查看结果,如下:

  • 使用 var 的时候:
for(var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 1000)
}
// 5 5 5 5 5

解释:我们知道,循环结束的条件是 i = 5。从事件循环机制的角度来分析上面的代码,是这样的:

  • 首先在 Call Stack 中执行同步代码 var i = 0,此时 i 小于5,执行下一行代码,发现是一个 setTimeout 计时器,它是一个宏任务,这个时候会被推入到 WEB API 中,计时器开始执行;
  • 执行i++,在Call Stack 中进入下一次迭代循环,重复上面的操作。

其实上面的代码中 WEB API 一共存放过 5 个计时器,每个计时器进入到 WEB API,1s 之后就会被推入到 QUEUE 中(最后队列中也会有 5 个计时器),等待 EVENT LOOP 检测到 Call Stack 为空时,将 QUEUE 中每一个计时器推入到 Call Stack 执行,最后全部代码执行完成,从调用栈中退出。

使用 var 的时候,由于每一次循环得到的迭代变量会被上一次的覆盖,最后 i 等于 5,退出循环,迭代变量也被泄露出去了,每一个计时器引用同一个 i,因此会打印 5 个 5。

  • 使用 let 的时候:
for(let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 1000)
}
// 0 1 2 3 4

解释:和使用 var 声明迭代变量是一样的:循环结束的条件是 i = 5,内部的事件循环机制也同理。但是,使用 let 声明迭代变量的情况下,会为每一个迭代循环声明一个独立的迭代变量,因此每一个计时器中的 i 都是唯一的,最后输出 0 1 2 3 4,也不难理解。

文章到此结束,希望能够帮助得到大家,觉得有用可以点个赞,同时欢迎评论区交流。

你可能感兴趣的:(javascript,前端,开发语言)