JS 函数的执行时机

201 阅读1分钟

在说这个问题之前,我们先来看一下下面这段代码:

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

这段代码的运行结果会让控制台打印出6个6,这是为什么呢?

setTimeout语句把console.log(i)放入等待区,等待当前语句全部执行完后,调用等待区中的6个console.log(i)。而第一句代码let i = 0会在最外部的环境声明一个变量i,而for循环中的每一次循环时用到的变量i,都是同一个变量。在for循环全部执行完毕后,内存中变量i的值变为6,这时等待区的console.log(i)语句中的i,全部都是内存中已经变为6的i变量,因此会打印出6个6。

打印出0,1,2,3,4,5的方法

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

仅仅是把i的定义放入循环条件中初始化,就能简单的实现按顺序打印i的值。这是因为在循环条件中初始化的i,实际上在每一次循环时,都将该值复制一份放在当前循环体中使用。

  1. ES6以前的办法:
for(var i = 0; i < 6; i++){
    (function(i){
        setTimeout(function(){
            console.log(i);
        },0);
    })(i);
}

在ES6以前要想实现类似的效果,就必须使用闭包来实现,循环体中的匿名函数可以使用外层for循环作用域的变量i,原理是把每一次循环的var i的值复制一份当做参数传递给匿名函数,用这种方法实现预期效果。