JS之For循环内异步操作,总是得到最后一次循环变量?

一道经典的面试题,也是在日常开发中经常会遇到的问题。
如下代码:

for(var i=0; i<5; i++) {
  setTimeout(function() {
    console.log(i)
  },1000)
}

执行后发现他神奇的输出了5,5,5,5,5。而不是0,1,2,3,4
原因是因为for循环不会等待异步任务执行结果。原理:Js是单线程的,这就意味着所有任务需要放入任务队列,一件事干完才能下一件事。异步任务会放在执行栈的尾部,当所有同步任务执行完,才会执行异步任务。所以当for循环结束,最后一次i++的时候变量i已经是5了,然后再依次执行5次这个setTimeout里的函数体,因此打印出了5,5,5,5,5

解决方法:
方法1:var 改为 let,因为let 声明的变量只在 let 命令所在的代码块内有效。

for(let i=0; i<5; i++) {
  setTimeout(function() {
    console.log(i)
  },1000)
}
//输出0,1,2,3,4

方法2:使用try...catch,因为catch花括号内是一个块级作用域,可以保存循环变量,产生类似闭包效果。

for(var i=0; i<5; i++) {
  try{
    throw(i)
  } catch(j) {
    setTimeout(function() {
      console.log(j)
    },1000)
  }
}
//输出0,1,2,3,4

方法3:使用自执行函数,产生闭包作用域。

for(var i=0; i<5; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i)
    },1000)
  })(i)
}
//输出0,1,2,3,4

你可能感兴趣的:(JS之For循环内异步操作,总是得到最后一次循环变量?)