6个6面试题

366 阅读3分钟

6个6

let i
for(i=0;i<6;i++){
    setTimeout(()=>console.log(i),1000)
}

这段代码最后会打印出6个6.

i=0setTimeout(console.log(i),1000),1s后,打印i。有人说,现在i=0啊,为什么不是打印0?因为现在 console.log 这个函数还没有执行,只是定义。没执行的时候,js不会去管里边的内容。

i=1setTimeout(console.log(i),1000),1s后,还是打印i,而不是1。

一直到 i=5 。然后 i=6 ,跳出循环。for 循环结束了,看看这时到没到1s,如果没到,那就不会去打印。到了1s了,而且现在还不忙,那就去执行函数。

如果后续函数用时很长,那就会在后续函数执行完后再去执行setTimeout,即setTimeout(fn(),1000)表示1000ms后尽快执行,也就说他只限制了1000ms内不可以执行。

执行的函数是:console.log(i),执行时查看i是几。现在i=6,那就打印6。 后续还有五个函数,console.log(i)i还是6,那就一直打印6.

所以最后的结果就是,打印6个6。

总结:函数在调用的时候才会执行,执行时才会看变量值。

怎么打印0,1,2,3,4,5?

之所以会打印出6个6 ,是因为函数没执行的时候,不会去看里边的值。i 从0到1,0这个值就没了,以此类推,中间的值都没了。

那我们把中间的值保存下来,打印这个保存下来的值不就好了。

let i
for(i=0;i<6;i++){
    let j=i
    setTimeout(console.log(j),1000)
}

i=0let j=0 ,setTimeout(console.log(j),1000) 1s后,打印j

i=1let j=1 ,setTimeout(console.log(j),1000) 1s后,打印j

有人说,i=1的时候,j不是变成1了吗,那第一个打印j,打印出来的不就是新的值了吗?

注意,let 是有作用域的,它的作用域是从 { 开始,到 } 结束。也就是说,每次循环,都是一个新的作用域,在每个新的作用域里,j 其实是不同的,互不干扰的。

i=0 时,第一个作用域里,j=0 ,那就一直是0。

i=1 时,又是一个新的作用域了,在这个新的作用域里,j=1 ,那就一直是1。

其实本质就是 j1,j2,j3 ,是不同的。

所以最后会打印出0,1,2,3,4,5

语法糖

因为其实第二种才是正常的可以理解的结果,所以js直接给了一个语法糖,你不用自己写 let j=i 这句话了,在for循环的 i 前边加一个 let ,就会有同样的效果。

for(let i=0;i<6;i++){
    setTimeout(console.log(i),1000)
}

结果:打印0,1,2,3,4,5

加一个let ,就会在每次进入循环后,自动为我们创建一个隐形的i',就像j一样,打印的其实是这个i',它会保存下中间的值

立即执行函数

除了用 let 保存中间值外,还有第二种方法,就是立即执行函数。

image.png

var 没有作用域。

每次循环,马上执行一个匿名函数,把每次的 i 作为实参,传给它的形参。因为这个匿名函数执行了,所以它里边的 j(j叫i也可以,最前面的括号是形参,最后面的是实参) 就确定了值,就是每次的0,1,2,3,4,5。所以 for 循环结束以后,就会打印出已经定好的0,1,2,3,4,5