• 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) 无效,也不会报错。


    欢迎访问:天问博客

  • 相关阅读:
    数据一致性:双删为什么要延时?
    Python爬虫爬图片测试1
    数据结构与算法——线性查找法
    通过位运算进行两个变量值的交换功能
    奇迹mu服务端开服架设技术搭建Data文件说明
    【JAVA数据结构】JAVA数据结构必备知识:泛型与包装类
    十五、异常(4)
    CTFHub | MySQL结构
    java计算机毕业设计废旧物品回收管理系统MyBatis+系统+LW文档+源码+调试部署
    redis常用5大数据类型
  • 原文地址:https://blog.csdn.net/tiven_/article/details/126310598