高级前端
js
【Q566】关于块级作用域,以下代码输出多少,在何时间输出

关于块级作用域,以下代码输出多少,在何时间输出

更多描述

for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 1000);
}

Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 581 (opens in a new tab)

Author 回答者: shfshanyue (opens in a new tab)

一秒之后连续输出五个5,以下可输出预期效果

for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 1000 * i);
}
 
for (var i = 0; i < 5; i++) {
  setTimeout(console.log, 1000 * i, i);
}

Author 回答者: aotushi (opens in a new tab)

一秒之后连续输出五个5,以下可输出预期效果

for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 1000 * i);
}
 
for (var i = 0; i < 5; i++) {
  setTimeout(console.log, 1000 * i, i);
}

为什么setTimeout格式不同,输出的结果也不同.例如:当for循环采用var声明变量,但setTimeout(console.log,1000*i,i)与setTimeout(()=>console.log(i),0)输出的结果不一样.

是因为函数作用域?

Author 回答者: hwb2017 (opens in a new tab)

第一种使用var的方式:

for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 1000);
}

第二种使用var的方式:

for (var i = 0; i < 5; i++) {
  setTimeout(console.log, 1000 * i, i);
}

var 声明的变量是在函数作用域或者全局作用域的,在第一种方式中,由于setTimeout是异步执行,且它是从闭包中获取 i 变量,由于 i 是在函数/全局作用域中声明的,所以5次循环中 i 不断被赋值,最后 i 的值为5,执行的结果为连续的5个5。

在第二种方式中,通过给setTimeout的回调函数传参的方式,保存了每次循环中 i 的值,因此执行结果符合预期

let声明的变量是在块级作用域(花括号)中的,因此可以认为每次执行循环语句块中的 i 变量是互相独立的,所以执行结果也符合预期