JavaScript for循环中var替代let为何返回undefined
为什么for循环中用var代替let会返回undefined
核心原因是var和let的作用域规则差异,结合setTimeout的异步执行特性共同导致。
运行逻辑拆解
首先明确基础前提:setTimeout的回调是异步宏任务,不会在循环执行时立刻运行,会等所有同步代码(也就是整个for循环)执行完毕、调用栈清空后,才会等到定时触发执行回调。
let声明循环变量的场景
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let i = 0; i < 10; i++) { setTimeout(() => console.log(a[i]), 3000); }
运行结果:3秒后依次输出1,2,3,4,5,6,7,8,9,10
- 原理:
let遵循块级作用域规则,for循环的每一次迭代都会生成一个独立的i变量绑定,每个setTimeout回调捕获的都是当前迭代专属的i值。等回调执行时,拿到的就是对应轮次的0-9索引,访问数组元素自然返回正确结果。
var声明循环变量的场景
var i = 0; for (i = 0; i < 10; i++) { setTimeout(() => console.log(a[i]), 3000); }
运行结果:3秒后输出10个undefined
- 原理:
var没有块级作用域,无论在循环内还是循环外声明,整个运行环境中只有一个全局共享的i变量。for循环同步执行的速度远快于3秒定时,等回调开始执行时,循环早就跑完了,此时共享的i值已经累加到10(循环终止条件是i < 10,最后一次i++后i变为10才跳出循环)。而数组a的有效索引范围是0-9,访问a[10]这个不存在的索引就会返回undefined,10个回调都访问同一个i=10,自然全输出undefined。
补充:如果要在var的写法下拿到正确结果,可以借助闭包或者给setTimeout传第三个参数固定每次的i值,比如:
for (var i = 0; i < 10; i++) { setTimeout((val) => console.log(a[val]), 3000, i); }
内容的提问来源于stack exchange,提问作者Cpt Kitkat
相关产品推荐
相关产品推荐

