for循环+setTimeout遇到的问题(settimeout())
以下代码会打印5次5,而不会依次打印0~4:
for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i) }, 1000) } 复制代码
原因:通过var声明的变量会发生变量提升。即等价于以下代码:
var i; // i为全局变量 for (i = 0; i < 5; i++) { setTimeout(() => { console.log(i) }, 1000) } // 或者下面这样展示更直观 var i; // i为全局变量 for (i = 0; i < 5; i++) { } // i==5了 setTimeout(() => { console.log(i) // 5 }, 1000) setTimeout(() => { console.log(i) // 5 }, 1000) setTimeout(() => { console.log(i) // 5 }, 1000) setTimeout(() => { console.log(i) // 5 }, 1000) setTimeout(() => { console.log(i) // 5 }, 1000) 复制代码
静态代码执行完时(i=5时跳出循环),全局变量i
就已经变为5了。由于setTimeout要等静态代码执行完,即for循环执行完,且过了1s之后才会执行setTimeout。因此执行setTimeout时,传入的全局变量i
的最终值:5。效果就是打印5次5。
解决方法:
方法1:给setTimeout封装到一个局部函数,每个局部函数都拥有一个独立的作用域,内部的变量会遮蔽全局作用域的同名变量,也不会受其他代码块的影响,俗称闭包。
for (var i = 0; i < 5; i++) { ( // 形参m由i赋值 function (m) { setTimeout(() => { console.log(m) }, 1000); } )(i) } 复制代码
方法2:使用let或const关键词
for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i) }, 1000) } 复制代码
方式3:块级作用域
for (var i = 0; i < 5; i++) { { // {}内添加一个let或const后,会成为块作用域 let j = i; setTimeout(() => { console.log(j); }, 1000); } } 复制代码
以上内容含自己的理解,仅用于自学记录。
作者:carryon
链接:https://juejin.cn/post/7038989303623450660
伪原创工具 SEO网站优化 https://www.237it.com/