• 解决 for 循环中使用 var 定义函数的问题(解决循环中异步问题)


    结论先行:

    因为 setTimeout 为宏任务,根据 JS 的事件循环机制,当主线程同步任务执行完成之后才会去执行宏任务。这时候 for 循环已经全部执行完毕,i 就是最后的值了。

    解决办法:

    ① 使用立即执行函数将 i 传入函数内部,这个时候值就被固定在了参数 j 上不会改变;当下次执行 timer 这个闭包的时候,就可以使用外部函数的变量 j , 从而达到目的。 

    ② 使用 setTimeout 的第三个参数这个参数会被当成 timer 函数的参数传入。原理类似于方法①

    ③ 使用 let 定义 i 【推荐】。因为 let 可以定义块级作用域,所以不存在变量覆盖的问题。

     

    具体分析:

    1、问题 

    首先,因为 setTimeout 是个异步函数,所以会先把 for 循环全部执行完毕,这时候 i 就是 6了,所以会输出 5 个 6

    因为 setTimeout 为宏任务,由于JS 中单线程 eventLoop 机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后 setTimeout 中的回调才依次执行。

    而且, setTimeout 函数也是一种闭包,往上找它的父级作用域链就是 window,变量 i 为 window 上的全局变量,开始执行 setTimeout 之前变量 i 已经就是 6了,因此最后输出 5 个 6

    1. for(var i = 1; i <= 5; i++) {
    2. setTimeout(function timer() {
    3. console.log(i) // 打印6 6 6 6 6
    4. }, i * 1000)
    5. }

    2、解决办法

    ①  利用 IIFE (立即执行函数)

    使用立即执行函数将 i 传入函数内部,这个时候值就被固定在了参数 j 上不会改变;当下次执行 timer 这个闭包的时候,就可以使用外部函数的变量 j , 从而达到目的。 

    1. for(var i = 1; i <= 5; i++) {
    2. (function(j) {
    3. setTimeout(function timer() {
    4. console.log(j) // 打印1 2 3 4 5
    5. }, j * 1000)
    6. })(i)
    7. }

    ②  使用 setTimeout 的第三个参数

    setTimeout 作为经常使用的定时器,它是存在第三个参数的。我们经常使用前两个,一个是回调函数,另外一个是定时时间,setTimeout 从第三个入参位置开始往后,是可以传入无数个参数的。

    这些参数会作为回调函数的附加参数存在。

    这个参数会被当成 timer 函数的参数传入

    1. for(var i = 1; i <= 5; i++) {
    2. setTimeout(function timer(j) {
    3. console.log(j)
    4. }, i * 1000, i)
    5. }

    ③  使用 let 定义 i 【推荐】

    let 可以定义块级作用域,因为在异步的时候不存在变量覆盖的问题。

    ES6 中新增的 let 定义变量的方式,使得 ES6 之后 JS 发生革命性的变化,让 JS 有了块级作用域,代码的作用域以块级为单位进行执行。

    可以看到,通过 let 定义变量的方式,重新定义 i 变量,则可以用最少的改动成本,解决该问题。 

    1. for(let i = 1; i <= 5; i++) {
    2. setTimeout(function timer() {
    3. console.log(i)
    4. }, i * 1000)
    5. }

  • 相关阅读:
    深入理解HTTPS协议原理
    C++ 构造函数不能是虚函数的原因
    CIO们开始将软件供应链升级为安全优先级top
    [附源码]计算机毕业设计基于Springboot学生社团信息管理系统
    LeetCode220726_50、填充每个节点的下一个右侧节点指针
    华为OD机考算法题:支持优先级的队列
    【java期末复习题】第3章 运算符与流程控制
    全国流通经济杂志全国流通经济杂志社全国流通经济编辑部2022年第25期目录
    Dubbo底层网络连接模型
    React Hooks 源码学习
  • 原文地址:https://blog.csdn.net/qq_38290251/article/details/133710020