本文默认处于折叠状态,可点击标题后方的 展开或闭合。

参考链接:

  1. https://muyiy.cn/question/js/33.html

JavaScript

节流和防抖

  1. 防抖:动作发生后,延时多久后执行动作回调

    比如:点击事件,点击之后在一定时间后触发回调,在该时间内如果再发生点击事件 不会立即触发回调,而是重置延时触发时间。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
      function debounce(fn, time) {
        let timer = null
    
        return function() {
          clearTimeout(timer)
          timer = setTimeout(() => fn.apply(this, arguments), time)
        }
      }
    
      function log(time) {
        setTimeout(() => console.log('x: ' + time), time || 10)
      }
      const dlog = debounce(log, 100)
      dlog(10)
      dlog(50)
      dlog(100)
      dlog(120)
    
    x: 120
    

    10, 50, 100 都没触发,因为执行间隔都不超过 100 所以被 clearTimeout 取消了, 知道第四个 dlog(120) 调用,后面没有了,得到执行输出结果。

  2. 节流:两个动作触发有一定的时间间隔

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
      function throttle(fn, duration) {
        let last = 0
    
        return function() {
          let current = Date.now()
    
          if (current - last < duration) return
    
          fn.apply(this, arguments)
    
          last = Date.now()
        }
      }
    
      function log(time) {
        console.log('x: ' + time)
      }
    
      function delay(time) {
        setTimeout(() => dlog(time), time)
      }
    
      // 100ms 间隔
      const dlog = throttle(log, 100)
    
      delay(10)
      delay(50)
      delay(150)
      delay(160)
      delay(270)
    
    x: 10 // now - 0 >= 100
    x: 150 // 150 - 50 >= 100
    x: 270 // 270 - 160 >= 100
    
  3. 防抖和节流区别

    防抖 是指同一种类型的动作无论发生多少次,只要间隔时间不够长,就永远只会触发 最后那一个动作回调

    节流 是指两个动作中间必须间隔特定的时间,否则后面的动作不会触发,即在这固 定的时间间隔之内的动作会被忽略, 只会执行第一个动作回调

测试:

移动鼠标到我上面移动,离开时重置,移动时观察蓝条变化,停止时观察红条变化
debounce
throttle

下面的代码打印什么?

IIFE 函数名是个常量?

函数定义实现原理: http://ecma-international.org/ecma-262/5.1/#sec-13

博客内伪码链接 ->>

  1. 非严格模式

    1
    2
    3
    4
    5
    6
    
      var b = 10
    
      ;(function b() {
        b = 20
        console.log(b)
      })()
    
    [Function: b]
    

    输出结果分析:非严格模式下 IIFE 的函数名不能进行赋值,如果赋值了的话静默是失 败的,所以说 b = 20 这一句没其任何作用,函数内部的 b 还是 IIFE 的那个函数 名,所以最后输出依旧是 [Function: b]

  2. 严格模式

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
      var b = 10
    
      try {
        ;(function b() {
          "use strict";
          b = 20
          console.log(b)
        })()
      } catch(e) {
        console.log(e)
      }
    
    TypeError Assignment to constant variable.
    

    结果分析:将 IIFE 内部换成严格模式就能很明显的说明问题了,上面结果报错“不能给 常量赋值”,立即函数名是不可变的常量。

  3. window.b/this.b

    1
    2
    3
    4
    5
    6
    7
    8
    
      var b = 10;
    
      (function b() {
        b = 20
    
        console.log(b)
        console.log(this.b) // 10
      })()
    
    [Function: b]
    10
    

    因为这里是以 node module 环境运行的,所以不能直接使用 window.b/this.b/global.b 去取到外面的 var b = 10 的值,结果是根据浏览器环境 运行结果。

    第二个 log 结果是 10 ,原因是在全局作用域下用 var 声明的变量是全局变 量,会挂到 window 对象下面,所以可以直接通过 window.b 取到它的值,用 this.b 也能取到是因为 IIFE 函数调用上下文是在全局,所以 this 指向 window

  4. 函数提升(声明+赋值)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
      var b = 10
    
      function b() {
        b = 20
        console.log(b)
      }
    
      console.log({ b })
      try {
        b()
      } catch(e) {
        console.log(e.message)
      }
    
    { b: 10 }
    b is not a function
    

    结果分析:提升对于命名式函数表达式来说,它的声明和赋值都会被提升,对于 var 声明的变量只会提升声明,所以就有

    1. function b 声明和赋值提升, var b 声明提升,由于声明只会发生一次, 所以这里相当于只有一次声明和赋值,即此时有变量 b 它的值是 function b() {}

    2. 但是 var b = 10 的赋值不会提升,所以当执行到这一句的时候, b 的值 会被这里的赋值操作给替换成 10

  5. 只有 b = 10

    1
    2
    3
    4
    5
    6
    7
    8
    
      function b() {
        console.log(b) // [Function b]
        b = 1
        console.log(window.b) // 1
        console.log(b) // 1
      }
    
      b()
    
    [Function b]
    1
    1