JS 函数的执行时机

先看以下例子:

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

这个例子的结果是:打印出 6 个 6。

来分析下它的结果:

  • 首先:setTimeout() 函数的意思是过一会再执行,在这个例子里,会过一会再打印出 i 的值。显然,for 循环会让 setTimeout() 执行6次,结果会打印6次 i 的值。
  • 可为什么6次取的 i 值都是 6,而不是 0,1,2,3,4,5 呢?
    这是因为JS的闭包,是先记录“变量名”,等需要用到的时候再去取“变量值”。 for 循环每执行一次,都有一个 setTimeout() 记录要调用外部变量 i ,但每次只记录变量名为 i 而不取值;for 循环结束后(i = 6),setTimeout() 才去取出外部变量 i 的值。每次 setTimeout() 打印出一个6,故6次 setTimeout() 共打印出6个6 。
  • 那为什么for 循环结束了,setTimeout() 才会去取外部变量的值?
    参考这位同学的博客:JS 函数的执行时机
    简单来说就是:JS是单线程环境,会优先执行完所有的同步任务(如 for 循环),再执行异步任务(for循环每执行一次,会把一个 setTimeout() 插入异步任务队列),因此 for 循环全部结束,才会从任务队列中取出 setTimeout() 来执行。

那么,怎么让它输出0,1,2,3,4,5呢?

可以 for 和 let 配合,let 声明放 for 循环里面:

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

除了 for 和 let 配合,还有什么方法呢?

方法1:放弃setTimeout() 函数,直接输出

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

此外,参考其他同学的博客,有:

方法2:让每次 setTimeout() 调用的 i 变量均为独立的变量。

  • 比如用 JS 独有的立即执行函数:
let i=0
for(let i=0;i<6;i++) { 
    ! function(i){
        setTimeout(()=>console.log(i))
    }(i) 
}
  • 比如限定 i 的作用域,使它成为局部变量:
    可以通过把 setTimeout() 放进其他函数,再把 i 作为这个函数的形式参数
function log(j){
    setTimeout(function(){
        console.log(j);
    },0);
}
let i=0;
for(i = 0; i<6; i++){
  log(i);
}

方法3:利用setTimeout()函数的第三个参数

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

将 i 的值传入到函数中,那么之后就是输出 i 当时传进来时候的值,并不会跟随她之后的值而改变。

方法4:当然,也可以引入另外一个变量temp,用 temp 保存 i 的值

let i
for(i = 0; i<6; i++){
    let temp = i
    setTimeout(()=>{
      console.log(temp)
    })
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容