We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i) }, 0) }
因为在for循环里使用了 var 关键字,var会在上下文执行栈里创建环境记录项,在计时器内部每次访问的都是全局的i 所以每次的值都是相同的 为什么每次都是全局i? 因为var关键字没有块级作用域而且会变量提升,每次for循环就相当于:
var
i
var i = undefined for() { var i = 上一轮的i ... }
可以理解为在for里面使用var。根据变量提升,var会在for的上面先定义 然后每次for在重新定义同样的变量。所以每次修改的都是同一个变量
除了上述所说的var关键字的问题 还关系到setTimeout是一个宏任务,也可以说是一个异步回调。for执行时期,异步回调还没有开始执行。等for执行完毕 开始依次执行栈里的异步回调,这时回调里并没有定义i 变量,所以根据作用域链会向上寻找,寻找到了全局的i
i 变量
let
for
let i
不同的上下文执行栈
The text was updated successfully, but these errors were encountered:
No branches or pull requests
低端回答
因为在for循环里使用了
var
关键字,var
会在上下文执行栈里创建环境记录项,在计时器内部每次访问的都是全局的i
所以每次的值都是相同的
为什么每次都是全局
i
? 因为var关键字没有块级作用域而且会变量提升,每次for循环就相当于:可以理解为在for里面使用var。根据变量提升,var会在for的上面先定义 然后每次for在重新定义同样的变量。所以每次修改的都是同一个变量
高端回答
除了上述所说的
var
关键字的问题还关系到setTimeout是一个宏任务,也可以说是一个异步回调。for执行时期,异步回调还没有开始执行。等for执行完毕 开始依次执行栈里的异步回调,这时回调里并没有定义
i 变量
,所以根据作用域链会向上寻找,寻找到了全局的i
这个问题的根本原因是for循环里的回调函数的上下文执行栈中并没有保存
i
,根据作用域链 寻找上级的上下文执行栈那么如何解答呢?
1. 立即执行异步回调,或者使用变量将
i
保存到函数内部2. 使用
let
关键字。使用let
定义的变量会绑定在块级作用域内;ECMA对for的定义是:每次循环都会创建一个新的块级作用域,本轮循环的值指向上一轮的值(个人理解有赋值/指针指向的意思,而不是和上一轮是相同值)。所以总结一下就是
for
每次循环都会创建一个新的块级作用域,而且会在作用域里重新let i
。所以每轮的回调中的i
都指向了不同变量(不同的上下文执行栈
)这个问题的核心点就是:只要让
i
能保存在每轮循环的上下文执行栈里就没错The text was updated successfully, but these errors were encountered: