关于setTimeout与块级作用域的JS代码执行差异疑问
问题原因解析
核心在于let和var的作用域差异,以及闭包的变量捕获机制:
let i的块级作用域:用let声明循环变量时,每次循环迭代都会生成一个独立的i变量。每个循环里定义的logWrappper函数,会捕获当前迭代的i绑定。当setTimeout延迟执行这些logWrappper时,每个回调里的console.log(i)都会输出各自迭代时的i值,也就是0到9依次出现。var log的函数级作用域:var声明的变量作用域是函数级(这里是全局),所以每次循环都会把log覆盖成当前迭代创建的新函数。等所有setTimeout回调开始执行时,循环已经结束,此时log变量指向的是最后一次循环创建的log函数。- 闭包的变量捕获逻辑:最后一次循环里的
log函数,捕获的是当前迭代的i(也就是9,循环到i=9时执行循环体,之后i++变成10退出循环)。所以不管哪个logWrappper调用log,执行的都是这个最终的log函数,因此会连续输出10次9。
关于直接调用logWrappper的情况:
直接调用时,循环还在逐次迭代,每次调用logWrappper时,log刚被赋值为当前迭代的函数,它捕获的也是当前迭代的i,所以log和logWrappper里的输出都能对应0到9。
内容的提问来源于stack exchange,提问作者Wang Ningning
相关产品推荐
相关产品推荐

