Bus de eventos antivibración, aceleración y copia profunda

1 Comprender la antivibración y la aceleración

2 uso de subrayado

3 Optimización de la función antivibración

4 Optimización de la función del acelerador

5 Implementación de la función de copia profunda

6 Implementación de la herramienta de bus de eventos

En resumen, anti-vibración significa que si se activa un evento, se retrasará y se ejecutará nuevamente.

Acelerar significa ejecutarlo de vez en cuando, sin importar cuántas veces lo actives en el medio.

Antivibración: comprensión de las operaciones antivibración 

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>
  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 2.监听input元素的输入
    // let counter = 1
    // inputEl.oninput = function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }
    
    // 3.防抖处理代码
    let counter = 1
    inputEl.oninput = _.debounce(function() {
      console.log(`发送网络请求${counter++}:`, this.value)
    }, 3000)

  </script>

</body>

Anti-vibración - lograr anti-vibración - implementación básica (entrevista

Es necesario obtener la función ejecutada anteriormente para cancelar la función ejecutada anteriormente, esto se obtiene a través del temporizador let.

La ejecución retrasada se logra principalmente a través de temporizadores, y el temporizador tiene la función de establecer nulo para borrarlo.

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hydebounce(fn, delay) {
      // 1.用于记录上一次事件触发的timer
      let timer = null

      // 2.触发事件时执行的函数
      const _debounce = () => {
        // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
        if (timer) clearTimeout(timer)

        // 2.2.延迟去执行对应的fn函数(传入的回调函数)
        timer = setTimeout(() => {
          fn()
          timer = null // 执行过函数之后, 将timer重新置null
        }, delay);
      }

      // 返回一个新的函数
      return _debounce
    }
  </script>

  <script>
   

    // 3.自己实现的防抖
    let counter = 1
    inputEl.oninput = hydebounce(function() {
      console.log(`发送网络请求${counter++}`)
    }, 1000)

  </script>

</body>

Anti-vibración-implementar anti-vibración-esto y enlace de parámetros

El proceso de vinculación de este

Además, el evento dom tiene un evento de evento vinculado. Cuando escribimos hudebounce, en realidad estamos ejecutando _debounce, por lo que esta función tiene implícitamente vinculado inputEl, y este es inputEl. Y const _debounce = function(...args) puede obtener el evento y otros parámetros y pasarlos a la función fn.

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hydebounce(fn, delay) {
      // 1.用于记录上一次事件触发的timer
      let timer = null

      // 2.触发事件时执行的函数
      const _debounce = function(...args) {
        // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
        if (timer) clearTimeout(timer)

        // 2.2.延迟去执行对应的fn函数(传入的回调函数)
        timer = setTimeout(() => {
          fn.apply(this, args)
          timer = null // 执行过函数之后, 将timer重新置null
        }, delay);
      }

      // 返回一个新的函数
      return _debounce
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 未进行防抖处理代码
    // let counter = 1
    // inputEl.oninput = function(event) {
    //   console.log(`发送网络请求${counter++}:`, this, event)
    // }

    // 2.underscore防抖处理代码
    // let counter = 1
    // inputEl.oninput = _.debounce(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的防抖
    let counter = 1
    inputEl.oninput = hydebounce(function(event) {
      console.log(`发送网络请求${counter++}:`, this, event)
    }, 1000)

  </script>

</body>

Realización de la función anti-vibración-realización de anti-vibración-cancelación

El evento oninput se ejecutará después de la entrada. Podemos configurar un botón para cancelar la ejecución de este evento. La forma de implementarlo depende del código. La razón principal es que _debounce de hudebounce es un tipo de objeto, por lo que puede cancelar la ejecución directamente con la función.

<body>

  <button>按钮</button>

  <input type="text">
  <button class="cancel">取消</button>
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hydebounce(fn, delay) {
      // 1.用于记录上一次事件触发的timer
      let timer = null

      // 2.触发事件时执行的函数
      const _debounce = function(...args) {
        // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
        if (timer) clearTimeout(timer)

        // 2.2.延迟去执行对应的fn函数(传入的回调函数)
        timer = setTimeout(() => {
          fn.apply(this, args)
          timer = null // 执行过函数之后, 将timer重新置null
        }, delay);
      }

      // 3.给_debounce绑定一个取消的函数
      _debounce.cancel = function() {
        if (timer) clearTimeout(timer)
      }

      // 返回一个新的函数
      return _debounce
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    // 未进行防抖处理代码
    // let counter = 1
    // inputEl.oninput = function(event) {
    //   console.log(`发送网络请求${counter++}:`, this, event)
    // }

    // 2.underscore防抖处理代码
    // let counter = 1
    // inputEl.oninput = _.debounce(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的防抖
    let counter = 1
    const debounceFn = hydebounce(function(event) {
      console.log(`发送网络请求${counter++}:`, this, event)
    }, 5000)
    inputEl.oninput = debounceFn

    // 4.实现取消的功能
    cancelBtn.onclick = function() {
      debounceFn.cancel()
    }

  </script>

</body>

Antivibración - implementar antivibración - realizar funciones inmediatamente

El escenario de la aplicación puede ser que cuando el usuario ingresa al libro, se ejecutará inmediatamente cuando se ingrese b por primera vez, y el ook posterior tendrá un efecto anti-vibración. Dejemos que isInvoke se controle a través de otra variable.

<body>

  <button>按钮</button>

  <input type="text">
  <button class="cancel">取消</button>
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    // 原则: 一个函数进行做一件事情, 一个变量也用于记录一种状态

    function hydebounce(fn, delay, immediate = false) {
      // 1.用于记录上一次事件触发的timer
      let timer = null
      let isInvoke = false

      // 2.触发事件时执行的函数
      const _debounce = function(...args) {
        // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
        if (timer) clearTimeout(timer)

        // 第一次操作是不需要延迟
        if (immediate && !isInvoke) {
          fn.apply(this, args)
          isInvoke = true
          return
        }

        // 2.2.延迟去执行对应的fn函数(传入的回调函数)
        timer = setTimeout(() => {
          fn.apply(this, args)
          timer = null // 执行过函数之后, 将timer重新置null
          isInvoke = false
        }, delay);
      }

      // 3.给_debounce绑定一个取消的函数
      _debounce.cancel = function() {
        if (timer) clearTimeout(timer)
        timer = null
        isInvoke = false
      }

      // 返回一个新的函数
      return _debounce
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    // 未进行防抖处理代码
    // let counter = 1
    // inputEl.oninput = function(event) {
    //   console.log(`发送网络请求${counter++}:`, this, event)
    // }

    // 2.underscore防抖处理代码
    // let counter = 1
    // inputEl.oninput = _.debounce(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的防抖
    let counter = 1
    const debounceFn = hydebounce(function(event) {
      console.log(`发送网络请求${counter++}:`, this, event)
    }, 100)
    inputEl.oninput = debounceFn

    // 4.实现取消的功能
    cancelBtn.onclick = function() {
      debounceFn.cancel()
    }

  </script>

</body>

Anti-vibración-implementar anti-vibración-obtener el valor de retorno

Utilice promesas para obtener el valor de retorno.

<body>

  <button>按钮</button>

  <input type="text">
  <button class="cancel">取消</button>
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    // 原则: 一个函数进行做一件事情, 一个变量也用于记录一种状态

    function hydebounce(fn, delay, immediate = false, resultCallback) {
      // 1.用于记录上一次事件触发的timer
      let timer = null
      let isInvoke = false

      // 2.触发事件时执行的函数
      const _debounce = function(...args) {
        return new Promise((resolve, reject) => {
          try {
            // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
            if (timer) clearTimeout(timer)

            // 第一次操作是不需要延迟
            let res = undefined
            if (immediate && !isInvoke) {
              res = fn.apply(this, args)
              if (resultCallback) resultCallback(res)
              resolve(res)
              isInvoke = true
              return
            }

            // 2.2.延迟去执行对应的fn函数(传入的回调函数)
            timer = setTimeout(() => {
              res = fn.apply(this, args)
              if (resultCallback) resultCallback(res)
              resolve(res)
              timer = null // 执行过函数之后, 将timer重新置null
              isInvoke = false
            }, delay);
          } catch (error) {
            reject(error)
          }
        })
      }

      // 3.给_debounce绑定一个取消的函数
      _debounce.cancel = function() {
        if (timer) clearTimeout(timer)
        timer = null
        isInvoke = false
      }

      // 返回一个新的函数
      return _debounce
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    // 2.手动绑定函数和执行
    const myDebounceFn = hydebounce(function(name, age, height) {
      console.log("----------", name, age, height)
      return "coderwhy 哈哈哈哈"
    }, 1000, false)

    myDebounceFn("why", 18, 1.88).then(res => {
      console.log("拿到执行结果:", res)
    })

  </script>

</body>

Anti-vibración - lograr anti-vibración - encapsular archivos independientes

Código encapsulado:


// 原则: 一个函数进行做一件事情, 一个变量也用于记录一种状态
function hydebounce(fn, delay, immediate = false, resultCallback) {
  // 1.用于记录上一次事件触发的timer
  let timer = null
  let isInvoke = false

  // 2.触发事件时执行的函数
  const _debounce = function(...args) {
    return new Promise((resolve, reject) => {
      try {
        // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
        if (timer) clearTimeout(timer)

        // 第一次操作是不需要延迟
        let res = undefined
        if (immediate && !isInvoke) {
          res = fn.apply(this, args)
          if (resultCallback) resultCallback(res)
          resolve(res)
          isInvoke = true
          return
        }

        // 2.2.延迟去执行对应的fn函数(传入的回调函数)
        timer = setTimeout(() => {
          res = fn.apply(this, args)
          if (resultCallback) resultCallback(res)
          resolve(res)
          timer = null // 执行过函数之后, 将timer重新置null
          isInvoke = false
        }, delay);
      } catch (error) {
        reject(error)
      }
    })
  }

  // 3.给_debounce绑定一个取消的函数
  _debounce.cancel = function() {
    if (timer) clearTimeout(timer)
    timer = null
    isInvoke = false
  }

  // 返回一个新的函数
  return _debounce
}

código ejecutado html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <input type="text">
  <button class="cancel">取消</button>

  <script src="./js/hy_debounce.js"></script>
  <script>
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    let counter = 1
    const debounceFn = hydebounce(function(event) {
      console.log(`发送网络请求${counter++}:`, this, event)
    }, 1000)
    inputEl.oninput = debounceFn

    // 4.实现取消的功能
    cancelBtn.onclick = function() {
      debounceFn.cancel()
    }
  </script>
</body>
</html>

Acelerar: comprender las operaciones de aceleración

Utilice bibliotecas de terceros

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>
  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

  

    // 4.节流处理代码
    let counter = 1
    inputEl.oninput = _.throttle(function() {
      console.log(`发送网络请求${counter++}:`, this.value)
    }, 1000)

  </script>

</body>

Aceleración - Realización de la aceleración - Implementación básica (entrevista)

Se necesita una fórmula de cálculo para lograr el efecto estrangulador.

const tiempo de espera = intervalo - (tiempoahora - tiempo de inicio)

waitTime se utiliza para determinar si se debe ejecutar la función fn

intervalo es el intervalo de ejecución especificado por el usuario

nowTime es el punto de tiempo que registra cada ejecución de hythrottle.

startTime registra el punto de tiempo en el que se ejecuta fn cada vez y determina si se ejecuta la función fn mediante el juicio if.

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hythrottle(fn, interval) {
      let startTime = 0

      const _throttle = function() {
        const nowTime = new Date().getTime()
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          fn()
          startTime = nowTime
        }
      }

      return _throttle
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1
    inputEl.oninput = hythrottle(function() {
      console.log(`发送网络请求${counter++}:`, this.value)
    }, 1000)


  </script>

</body>

Acelerador-implementar estrangulamiento-esto y enlace de parámetros

El principio de implementación es el mismo que el del anti-vibración anterior, utilizando el método de enlace implícito. fn.apply(esto, argumentos)

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hythrottle(fn, interval) {
      let startTime = 0

      const _throttle = function(...args) {
        const nowTime = new Date().getTime()
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          fn.apply(this, args)
          startTime = nowTime
        }
      }

      return _throttle
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1
    inputEl.oninput = hythrottle(function(event) {
      console.log(`发送网络请求${counter++}:`, this.value, event)
    }, 1000)

  </script>

</body>

Acelerar - acelerar el implemento - realizar el control inmediatamente

Ya sea para ejecutar inmediatamente y la última ejecución.

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hythrottle(fn, interval, leading = true) {
      let startTime = 0

      const _throttle = function(...args) {
        // 1.获取当前时间
        const nowTime = new Date().getTime()

        // 对立即执行进行控制
        if (!leading && startTime === 0) {
          startTime = nowTime
        }

        // 2.计算需要等待的时间执行函数
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          fn.apply(this, args)
          startTime = nowTime
        }
      }

      return _throttle
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1
    inputEl.oninput = hythrottle(function(event) {
      console.log(`发送网络请求${counter++}:`, this.value, event)
    }, 1000)

  </script>

</body>

Acelerador - aceleración del implemento - control de ejecución de cola (comprender)

A diferencia del anti-vibración, se debe ejecutar el último tiempo de anti-vibración, pero si no se alcanza el límite de tiempo, no se ejecutará el último tiempo de aceleración. La siguiente es la solución.

<body>

  <button>按钮</button>

  <input type="text">
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hythrottle(fn, interval, { leading = true, trailing = false } = {}) {
      let startTime = 0
      let timer = null

      const _throttle = function(...args) {
        // 1.获取当前时间
        const nowTime = new Date().getTime()

        // 对立即执行进行控制
        if (!leading && startTime === 0) {
          startTime = nowTime
        }

        // 2.计算需要等待的时间执行函数
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          // console.log("执行操作fn")
          if (timer) clearTimeout(timer)
          fn.apply(this, args)
          startTime = nowTime
          timer = null
          return
        } 

        // 3.判断是否需要执行尾部
        if (trailing && !timer) {
          timer = setTimeout(() => {
            // console.log("执行timer")
            fn.apply(this, args)
            startTime = new Date().getTime()
            timer = null
          }, waitTime);
        }
      }

      return _throttle
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1
    inputEl.oninput = hythrottle(function(event) {
      console.log(`发送网络请求${counter++}:`, this.value, event)
    }, 3000, { trailing: true })

  </script>

</body>

Acelerador - implementar aceleración - cancelar implementación de función

1

<body>

  <button>按钮</button>

  <input type="text">
  <button class="cancel">取消</button>
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hythrottle(fn, interval, { leading = true, trailing = false } = {}) {
      let startTime = 0
      let timer = null

      const _throttle = function(...args) {
        // 1.获取当前时间
        const nowTime = new Date().getTime()

        // 对立即执行进行控制
        if (!leading && startTime === 0) {
          startTime = nowTime
        }

        // 2.计算需要等待的时间执行函数
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          // console.log("执行操作fn")
          if (timer) clearTimeout(timer)
          fn.apply(this, args)
          startTime = nowTime
          timer = null
          return
        } 

        // 3.判断是否需要执行尾部
        if (trailing && !timer) {
          timer = setTimeout(() => {
            // console.log("执行timer")
            fn.apply(this, args)
            startTime = new Date().getTime()
            timer = null
          }, waitTime);
        }
      }

      _throttle.cancel = function() {
        if (timer) clearTimeout(timer)
        startTime = 0
        timer = null
      }

      return _throttle
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1

    const throttleFn = hythrottle(function(event) {
      console.log(`发送网络请求${counter++}:`, this.value, event)
    }, 3000, { trailing: true })

    inputEl.oninput = throttleFn

    cancelBtn.onclick = function() {
      throttleFn.cancel()
    }

  </script>

</body>

Acelerar-implementar aceleración-obtener el valor de retorno

1

<body>

  <button>按钮</button>

  <input type="text">
  <button class="cancel">取消</button>
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>

  <script>
    function hythrottle(fn, interval, { leading = true, trailing = false } = {}) {
      let startTime = 0
      let timer = null

      const _throttle = function(...args) {
        return new Promise((resolve, reject) => {
          try {
             // 1.获取当前时间
            const nowTime = new Date().getTime()

            // 对立即执行进行控制
            if (!leading && startTime === 0) {
              startTime = nowTime
            }

            // 2.计算需要等待的时间执行函数
            const waitTime = interval - (nowTime - startTime)
            if (waitTime <= 0) {
              // console.log("执行操作fn")
              if (timer) clearTimeout(timer)
              const res = fn.apply(this, args)
              resolve(res)
              startTime = nowTime
              timer = null
              return
            } 

            // 3.判断是否需要执行尾部
            if (trailing && !timer) {
              timer = setTimeout(() => {
                // console.log("执行timer")
                const res = fn.apply(this, args)
                resolve(res)
                startTime = new Date().getTime()
                timer = null
              }, waitTime);
            }
          } catch (error) {
            reject(error)
          }
        })
      }

      _throttle.cancel = function() {
        if (timer) clearTimeout(timer)
        startTime = 0
        timer = null
      }

      return _throttle
    }
  </script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1

    const throttleFn = hythrottle(function(event) {
      console.log(`发送网络请求${counter++}:`, this.value, event)
      return "throttle return value"
    }, 3000, { trailing: true })

    throttleFn("aaaa").then(res => {
      console.log("res:", res)
    })

  </script>

</body>

Acelerar-implementar limitación-encapsular archivos independientes

guión bajo.js

function hythrottle(fn, interval, { leading = true, trailing = false } = {}) {
  let startTime = 0
  let timer = null

  const _throttle = function(...args) {
    return new Promise((resolve, reject) => {
      try {
         // 1.获取当前时间
        const nowTime = new Date().getTime()

        // 对立即执行进行控制
        if (!leading && startTime === 0) {
          startTime = nowTime
        }

        // 2.计算需要等待的时间执行函数
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          // console.log("执行操作fn")
          if (timer) clearTimeout(timer)
          const res = fn.apply(this, args)
          resolve(res)
          startTime = nowTime
          timer = null
          return
        } 

        // 3.判断是否需要执行尾部
        if (trailing && !timer) {
          timer = setTimeout(() => {
            // console.log("执行timer")
            const res = fn.apply(this, args)
            resolve(res)
            startTime = new Date().getTime()
            timer = null
          }, waitTime);
        }
      } catch (error) {
        reject(error)
      }
    })
  }

  _throttle.cancel = function() {
    if (timer) clearTimeout(timer)
    startTime = 0
    timer = null
  }

  return _throttle
}

<body>

  <button>按钮</button>

  <input type="text">
  <button class="cancel">取消</button>
  
  <!-- CDN引入: 网络的js文件 -->
  <!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
  <!-- 本地引入: 下载js文件, 并且本地引入 -->
  <script src="./js/underscore.js"></script>
  <script src="./js/hy_throttle.js"></script>

  <script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")
    const cancelBtn = document.querySelector(".cancel")

    // 2.underscore节流处理代码
    // let counter = 1
    // inputEl.oninput = _.throttle(function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }, 1000)

    // 3.自己实现的节流函数
    let counter = 1
    const throttleFn = hythrottle(function(event) {
      console.log(`发送网络请求${counter++}:`, this.value, event)
      return "throttle return value"
    }, 3000)

    inputEl.oninput = throttleFn

  </script>

</body>

Relaciones de asignación que introducen copia profunda y copia superficial

La copia superficial consiste en copiar el valor de un tipo de objeto en otro objeto. Los dos objetos tienen el mismo valor, pero cuando el valor se modifica por separado, no habrá una asignación de referencia que afecte el valor del otro objeto, es decir, el memoria de los dos objetos. Las direcciones son diferentes y son dos tipos de objetos diferentes.

La copia profunda es una situación en la que se puede implementar una copia superficial en los objetos dentro del objeto en función de una copia superficial.

El primer método de copia profunda es usar el método JSON para convertirlo primero en una cadena y luego convertirlo en un objeto, luego los objetos en el objeto se pueden convertir en un objeto de copia profunda. Pero esto tiene la desventaja de que si hay una función o [Symbol()]: "abc" en el objeto, esto será ignorado y no se podrá obtener, el objeto circular no se puede usar (window.window.window.window).

  console.log(window.window === window)

    const info = {
      name: "why",
      age: 18,
      friend: {
        name: "kobe"
      },
      running: function() {},
      [Symbol()]: "abc",
      // obj: info
    }
    info.obj = info

    // 1.操作一: 引用赋值
    // const obj1 = info

    // 2.操作二: 浅拷贝
    // const obj2 = { ...info }
    // // obj2.name = "james"
    // // obj2.friend.name = "james"
    // // console.log(info.friend.name)

    // const obj3 = Object.assign({}, info)
    // // obj3.name = "curry"
    // obj3.friend.name = "curry"
    // console.log(info.friend.name)

    // 3.操作三: 深拷贝
    // 3.1.JSON方法
    // const obj4 = JSON.parse(JSON.stringify(info))
    // info.friend.name = "curry"
    // console.log(obj4.friend.name)
    // console.log(obj4)

    // 3.2.自己编写一个深拷贝函数(第三方库)

Copia profunda: uso básico de funciones de copia profunda

La herramienta para determinar si es un tipo de objeto (aquí excluyendo funciones y tipos de matriz) es_object.js

// 需求: 判断一个标识符是否是对象类型
function isObject(value) {
  // null,object,function,array
  // null -> object
  // function -> function -> true
  // object/array -> object -> true
  const valueType = typeof value
  return (value !== null) && ( valueType === "object" || valueType === "function" )
}

// const name = "why"
// const age = 18
// const foo = {}
// const bar = function() {}
// const arr = []

// console.log(isObject(null)) // false
// console.log(isObject(bar)) // true
// console.log(isObject(name)) // false
// console.log(isObject(foo)) // true
// console.log(isObject(arr)) // true

Función kernel para tipos de pares de copia profunda

Lo que se copia aquí es el caso en el que hay un objeto en el objeto.

  <script src="./js/is_object.js"></script>
  <script>
    // 深拷贝函数
    function deepCopy(originValue) {
      // 1.如果是原始类型, 直接返回
      if (!isObject(originValue)) {
        return originValue
      }

      // 2.如果是对象类型, 才需要创建对象
      const newObj = {}
      for (const key in originValue) {
        newObj[key] = deepCopy(originValue[key]);
      }
      return newObj
    }

    const info = {
      name: "why",
      age: 18,
      friend: {
        name: "kobe",
        address: {
          name: "洛杉矶",
          detail: "斯坦普斯中心"
        }
      }
    }

    const newObj = deepCopy(info)
    info.friend.address.name = "北京市"
    console.log(newObj.friend.address.name)

  </script>

copia profunda: copia de matriz de la función de copia profunda

Lo que se copia aquí es la situación en la que hay un tipo de objeto en la matriz.

<script src="./js/is_object.js"></script>
  <script>
    // 深拷贝函数
    function deepCopy(originValue) {
      // 1.如果是原始类型, 直接返回
      if (!isObject(originValue)) {
        return originValue
      }

      // 2.如果是对象类型, 才需要创建对象
      const newObj = Array.isArray(originValue) ? []: {}
      for (const key in originValue) {
        newObj[key] = deepCopy(originValue[key]);
      }
      return newObj
    }

    const books = [
      { name: "黄金时代", price: 28, desc: { intro: "这本书不错", info: "这本书讲了一个很有意思的故事" } },
      { name: "你不知道JavaScript", price: 99 },
    ]

    // const newBooks = [...books]
    // newBooks[0].price = 88
    // console.log(books[0].price)

    const newBooks = deepCopy(books)
    console.log(newBooks)

  </script>

copia profunda: otros tipos de funciones de copia profunda

Tipos especiales de conjuntos, funciones y símbolos.

 <script src="./js/is_object.js"></script>
  <script>
    // 深拷贝函数
    function deepCopy(originValue) {
      // 0.如果值是Symbol的类型
      if (typeof originValue === "symbol") {
        return Symbol(originValue.description)
      }

      // 1.如果是原始类型, 直接返回
      if (!isObject(originValue)) {
        return originValue
      }

      // 2.如果是set类型
      if (originValue instanceof Set) {
        const newSet = new Set()
        for (const setItem of originValue) {
          newSet.add(deepCopy(setItem))
        }
        return newSet
      }

      // 3.如果是函数function类型, 不需要进行深拷贝
      if (typeof originValue === "function") {
        return originValue
      }

      // 2.如果是对象类型, 才需要创建对象
      const newObj = Array.isArray(originValue) ? []: {}
      // 遍历普通的key
      for (const key in originValue) {
        newObj[key] = deepCopy(originValue[key]);
      }
      // 单独遍历symbol
      const symbolKeys = Object.getOwnPropertySymbols(originValue)
      for (const symbolKey of symbolKeys) {
        newObj[Symbol(symbolKey.description)] = deepCopy(originValue[symbolKey])
      }

      return newObj
    }

    const set = new Set(["abc", "cba", "nba"])
    const s1 = Symbol("s1")
    const s2 = Symbol("s2")
    const info = {
      name: "why",
      age: 18,
      friend: {
        name: "kobe",
        address: {
          name: "洛杉矶",
          detail: "斯坦普斯中心"
        }
      },

      // 1.特殊类型: Set
      set: set,

      // 2.特性类型: function
      running: function() {
        console.log("running~")
      },

      // 3.值的特殊类型: Symbol
      symbolKey: Symbol("abc"),

      // 4.key是symbol时
      [s1]: "aaaa",
      [s2]: "bbbb"
    }

    // for (let key in info) {
    //   console.log(key)
    // }

    // const symbol = Symbol()
    // console.log(typeof symbol)
    // console.log(isObject(symbol))

    const newObj = deepCopy(info)
    console.log(newObj)

  </script>

Copia profunda: referencia circular de la función de copia profunda

Si la variable en el tipo de objeto tiene una referencia a sí misma, se devolverá un error y se informará un error en un bucle infinito.

<script src="./js/is_object.js"></script>
  <script>
    // 深拷贝函数
    // let map = new WeakMap()
    function deepCopy(originValue, map = new WeakMap()) {
      // const map = new WeakMap()

      // 0.如果值是Symbol的类型
      if (typeof originValue === "symbol") {
        return Symbol(originValue.description)
      }

      // 1.如果是原始类型, 直接返回
      if (!isObject(originValue)) {
        return originValue
      }

      // 2.如果是set类型
      if (originValue instanceof Set) {
        const newSet = new Set()
        for (const setItem of originValue) {
          newSet.add(deepCopy(setItem))
        }
        return newSet
      }

      // 3.如果是函数function类型, 不需要进行深拷贝
      if (typeof originValue === "function") {
        return originValue
      }

      // 4.如果是对象类型, 才需要创建对象
      if (map.get(originValue)) {
        return map.get(originValue)
      }
      const newObj = Array.isArray(originValue) ? []: {}
      map.set(originValue, newObj)
      // 遍历普通的key
      for (const key in originValue) {
        newObj[key] = deepCopy(originValue[key], map);
      }
      // 单独遍历symbol
      const symbolKeys = Object.getOwnPropertySymbols(originValue)
      for (const symbolKey of symbolKeys) {
        newObj[Symbol(symbolKey.description)] = deepCopy(originValue[symbolKey], map)
      }

      return newObj
    }

    const info = {
      name: "why",
      age: 18,
      friend: {
        name: "kobe",
        address: {
          name: "洛杉矶",
          detail: "斯坦普斯中心"
        }
      },
      // self: info
    }
    info.self = info

    let newObj = deepCopy(info)
    console.log(newObj)
    console.log(newObj.self === newObj)


    // mitt
  </script>

Bus de eventos: implementación del bus de eventos

Uso de la comunicación entre archivos y componentes.

<body>

  <button class="nav-btn">nav button</button>
  
  <script>

    // 类EventBus -> 事件总线对象
    class HYEventBus {
      constructor() {
        this.eventMap = {}
      }

      on(eventName, eventFn) {
        let eventFns = this.eventMap[eventName]
        if (!eventFns) {
          eventFns = []
          this.eventMap[eventName] = eventFns
        }
        eventFns.push(eventFn)
      }
      
      off(eventName, eventFn) {
        let eventFns = this.eventMap[eventName]
        if (!eventFns) return
        for (let i = 0; i < eventFns.length; i++) {
          const fn = eventFns[i]
          if (fn === eventFn) {
            eventFns.splice(i, 1)
            break
          }
        }

        // 如果eventFns已经清空了
        if (eventFns.length === 0) {
          delete this.eventMap[eventName]
        }
      }

      emit(eventName, ...args) {
        let eventFns = this.eventMap[eventName]
        if (!eventFns) return
        eventFns.forEach(fn => {
          fn(...args)
        })
      }
    }


    // 使用过程
    const eventBus = new HYEventBus()

    // aside.vue组件中监听事件
    eventBus.on("navclick", (name, age, height) => {
      console.log("navclick listener 01", name, age, height)
    })

    const click =  () => {
      console.log("navclick listener 02")
    }
    eventBus.on("navclick", click)

    setTimeout(() => {
      eventBus.off("navclick", click)
    }, 5000);

    eventBus.on("asideclick", () => {
      console.log("asideclick listener")
    })


    // nav.vue
    const navBtnEl = document.querySelector(".nav-btn")
    navBtnEl.onclick = function() {
      console.log("自己监听到")
      eventBus.emit("navclick", "why", 18, 1.88)
    }

  </script>

</body>

Supongo que te gusta

Origin blog.csdn.net/weixin_56663198/article/details/131740602
Recomendado
Clasificación