JS 函数的执行时机

203 阅读1分钟

为什么打印出6个6

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

原因:在JS执行过程中,当同步代码和异步代码同时存在时,异步代码会在同步代码全部执行完成后再调用。setTimeout是异步代码(就算延迟为0也是异步),它会在代码最后执行。循环结束后,共有6个setTimeouti通过自增已经变成了6,此时执行6个setTimeout, 把i打出来,就得到6个6.

如何修改才能打印出1,2,3,4,5

  • letfor结合,利用let形成的块级作用域

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

    原因:每次进入循环, i的值都是当前块级作用域的i, 代码显示如下:

    (let i = 0) {
        setTimeout(()=>{
            console.log(i)
        },0)
    }
    
    (let i = 1) {
        setTimeout(()=>{
            console.log(i)
        },0)
    }
    
    (let i = 2) {
    ...
    
  • 利用IIFE(立即调用的函数表达式)

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

    原因:利用立即执行函数和闭包实现的。每一次循环立即调用的函数表达式得到的都是当前的i,这样内部函数就调用外部变量形成闭包,setTimeout执行时打印出的值就是当前立即执行函数拿到的i