• setTimeout引发的刨根问底


    setTimeout定时器)是JavaScript中一个比较重要且常用的方法,该方法用于在指定的毫秒数后调用函数或计算表达式。平时开发可能基本都是使用 setTimeout(fn, ms) 的形式,当然还有比较神奇的用法,特别是在前端面试中,经常被问到。

    JavaScript setTimeout

    一、setTimeout 介绍

    1. 定义: setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。

    2. 语法

    setTimeout(code, milliseconds, param1, param2, ...)
    setTimeout(function, milliseconds, param1, param2, ...)
    
    • 1
    • 2
    参数描述
    code/function必需。要调用一个代码串,也可以是一个函数。
    milliseconds可选。执行或调用 code/function 需要等待的时间,以毫秒计。默认为 0。
    param1, param2, …可选。 传给执行函数的其他参数(IE9 及其更早版本不支持该参数)。

    二、使用

    1. 第一个参数为 code 字符串形式:
    setTimeout("console.log('Hello setTimeout')", 2000)
    
    • 1
    1. 第一个参数为 function 函数形式(推荐):
    setTimeout(function(){
      console.log('Hello setTimeout')
    }, 2000)
    
    • 1
    • 2
    • 3
    1. 传参:
    setTimeout(function(params){
      console.log(`参数:${params}`)
      console.log('Hello setTimeout')
    }, 2000, 'setTimeout params')
    
    /* 打印输出 */
    
    // 参数:setTimeout params
    // Hello setTimeout
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    三、经典面试题

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

    输出: 开始输出一个 5,然后每隔一秒再输出一个 5,一共 5 个 5。
    解析: var声明的 i 变量提升

    1. 优化:输出 0 到 4,且每个间隔一秒
    for (var i = 0; i < 5; i++) {
      (function(i) {
        setTimeout(function() {
          console.log(i);
        }, i * 1000);
      })(i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解析: 自执行函数形成闭包,而 JS 函数中基本类型的参数传递是按值传递
    更加直观的形式:

    function output(i) {
      setTimeout(function() {
        console.log(i);
      }, i * 1000);
    }
    
    for (var i = 0; i < 5; i++) {
      output(i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 其他方法:
    • 利用 ES6 中的 let 声明的变量形成块级作用域
    for (let i = 0; i < 5; i++) {
      setTimeout(function() {
        console.log(i);
      }, 1000 * i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 利用 setTimeout 中第三个参数,保持参数的引用。
    for (var i = 0; i < 5; i++) {
      setTimeout(function(i) {
        console.log(i);
      }, 1000 * i, i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    四、举一反三

    1. 删除自执行函数的参数
    for (var i = 0; i < 5; i++) {
      (function() {
        setTimeout(function() {
          console.log(i);
        }, i * 1000);
      })(i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出: 开始输出一个 5,然后每隔一秒再输出一个 5,一共 5 个 5。

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

    直接看不太容易理解,拆解一下:

    for (var i = 0; i < 5; i++) {
      var fn = (function(i) {
        console.log(i);
      })(i);
      setTimeout(fn, i * 1000);
      
      // 相当于下边的
      // setTimeout(undefined, i * 1000)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出: 直接输出 0 到 4,中间没有间隔。
    解析: fn 接收的是一个没有返回值的自执行函数,所以这里的 fn 为 undefined,相当于执行了 setTimeout(undefined, i * 1000) 无效,也不会报错。


    欢迎访问:天问博客

  • 相关阅读:
    强化学习从基础到进阶-案例与实践[4]:深度Q网络-DQN、double DQN、经验回放、rainbow、分布式DQN
    Docker的资源配额
    sort内部实现原理
    C++调用C#的动态库dll
    springboot+Redis+AOP实现请求限流器
    OpenCV图像处理学习二十一,直方图比较方法
    【无标题】
    c++二叉树的进阶--二叉搜索树
    【编程实践】黑框框里的打字小游戏,但是汇编语言
    循序渐进了解如何使用JSR303进接口数据校验
  • 原文地址:https://blog.csdn.net/tiven_/article/details/126310598