zoukankan      html  css  js  c++  java
  • 异步、作用域、闭包--setTimeout在for循环中的思考

    题目:

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

    理想答案是输出:0,1,2,3

    实际答案是输出:4,4,4,4

    这道题看似简单,其实涉及了js中关于异步、作用域、闭包的问题

    首先settimeout是异步执行函数,执行settimeout函数时,会在主线任务外增加一个新的任务队列,10ms后往新的任务队列里面添加settimeout内部的任务,只有主线上的任务全部执行完,才会执行新的任务队列里的任务,当主线执行完成后,i的值是4,所以此时再去执行任务队列里的任务时,i全部是4了。

      于是上面题目就不难理解了:

       每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了4次,就放了4个任务,当主线程执行完成后,才进入任务队列里面执行。
       (注意:for循环从开始到结束的过程,需要维持几微秒或几毫秒。)
    解决方法:
     第1种 把var 变成let 改变作用域
         for(let i=0;i<=3;i++){ setTimeout(function() {  console.log(i)  }, 10);}
        输出的是:0,1,2,3
        因为for循环头部的let不仅将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;这个匿名函数的参数作用域 和 for参数的作用域 不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。

      第二种  给settimeout的内部函数加一个闭包,让其立即执行

    for(var i=0;i<=3;i++){
      setTimeout(
        (function() {
          console.log(i);
        })()//此函数会立即执行
      , 10);
    }

  • 相关阅读:
    398. Random Pick Index
    382. Linked List Random Node
    645. Set Mismatch
    174. Dungeon Game
    264. Ugly Number II
    115. Distinct Subsequences
    372. Super Pow
    LeetCode 242 有效的字母异位词
    LeetCode 78 子集
    LeetCode 404 左叶子之和
  • 原文地址:https://www.cnblogs.com/webwangjie/p/8617859.html
Copyright © 2011-2022 走看看