最近在学习 JS 函数,我发现一个特别有意思的问题:
let i = 0
for(i = 0; i<6; i++){
console.log(i)
}
以上的这一段代码打印出的结果是 0 1 2 3 4 5,我想大家应该都不会有任何疑问。
但是,加了一个定时器之后...
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
它打印的结果竟然变成了6个6,为此,我特地看了一下mdn文档,发现定时器的作用是把一段代码延后执行,哪怕设置的是0毫秒以后,那它也会等待其他 js 代码执行完才执行。
因此,这就很好理解了,for 循环执行完之后 i 的值为 6 ,上面一段代码是等for 循环执行完之后再打印 6 个 i ,那么结果是 6 个 6 便不足为奇了。
既然理解了前因后果,那有没有方法让它输出0 1 2 3 4 5呢?
答案是有的,以下这段代码打印的结果便是0 1 2 3 4 5。
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
看了这段代码,我想大家可能会有跟我一样的疑问,为什么在for循环外面 let i = 0,结果是6个6,在里面 let i = 0 ,结果就会是0 1 2 3 4 5呢?
于是,我猜想,我们可以把上面的for循环看成以下一段代码
{
let i = 0
setTimeout(()=>{
console.log(i)
},0)
}
{
let i = 1
setTimeout(()=>{
console.log(i)
},0)
}
{
let i = 2
setTimeout(()=>{
console.log(i)
},0)
}
{
let i = 3
setTimeout(()=>{
console.log(i)
},0)
}
{
let i = 4
setTimeout(()=>{
console.log(i)
},0)
}
{
let i = 5
setTimeout(()=>{
console.log(i)
},0)
}
由于 let 是只作用于当前块作用域内的,一目了然,打印结果就是 0 1 2 3 4 5。
如果以上思路是正确的,那么,我把 let 改成 const 是否可行呢?
for(const i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
很遗憾,它给我报了一个错误Error: Assignment to constant variable.> 0,你以为我这样就失败了吗?
请耐心继续往下看
在机缘巧合之下,我看到了知乎大V方大大写的一篇文章:我用了两个月的时间才理解 let
于是,我再大胆猜想
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
我可以把以上的这一段代码看成下面的一段代码
let i = 0
if(i<6){
let xxx = i
setTimeout(()=>{
console.log(xxx)
},0)
i++
}
这就能很好理解为什么只能用 let 而不能用 const 了
如果你此时对我的猜想还有疑问,那么请试试下面两段代码
let i = 0
for(i = 0; i<6; i++){
let xxx = i
setTimeout(()=>{
console.log(xxx)
},0)
}
let i = 0
for(i = 0; i<6; i++){
const xxx = i
setTimeout(()=>{
console.log(xxx)
},0)
}
它们最后输出的结果都是 0 1 2 3 4 5.