为什么这个限制函数中的事件监听器的行为是这样的?

问题描述

在我学习 throttling in javascript 时,我发现了一种我无法解释的事件侦听器行为。这是一个简单的节流功能

const btn=document.querySelector("#throttle"); 
      
    // Throttling Function 
    const throttleFunction=(func,delay)=>{ 
      
      // PrevIoUsly called time of the function 
      let prev = 0;  
      console.log(prev); //This gets called only once and it is even before the button is clicked
      return (...args) => { 
        // Current called time of the function 
        let Now = new Date().getTime();  
  
        // Logging the difference between prevIoUsly  
        // called and current called timings 
        console.log(Now-prev,delay);  //This however doesn't get called before the button is clicked
          
        // If difference is greater than delay call 
        // the function again. 
        if(Now - prev> delay){  
          prev = Now; 
  
          // "..." is the spread operator here  
          // returning the function with the  
          // array of arguments 
          return func(...args);   
        } 
      } 
    } 
    btn.addEventListener("click",throttleFunction(()=>{ 
      console.log("button is clicked") 
    },1500)); 
<button id="throttle">Click Me</button> 

我有两个问题。

  1. 为什么 let prev = 0; 只被调用一次?即为什么不 prev 每次调用函数时都会重置为 0?
  2. 我还注意到 let prev = 0; 在按钮被点击之前就被调用了,为什么会发生这种情况?为什么在点击按钮之前没有调用其余的函数

This 是我找到上面代码的地方。我在 MDN 上查看过 addEventListener 但无济于事。任何帮助将不胜感激。

解决方法

.addEventListener() 方法将一个函数的引用作为它的第二个参数,它可以在您的按钮被点击时调用。所以这样的事情将无法将函数添加为点击事件处理程序:

const sayHello = () => console.log("hello");
btn.addEventListener("click",sayHello());

在上面的 JavaScript 示例中:

  1. 看到对addEventListener()

    的调用
  2. 评估它的参数,这意味着调用 sayHello() 函数。

    2.1. sayHello() 运行并返回 undefined

  3. 使用 addEventListener()"click"(评估参数)调用 undefined 方法

sayHello() 上方是一个函数调用,因此它会在添加事件侦听器时以及在发生任何点击之前执行,从而导致 sayHello 的返回值被用作 { 的第二个参数{1}},因此上面的代码将评估为:

addEventListener()

要正确地将引用传递给事件侦听器,您需要传递一个函数,该函数随后可以在发生单击时由 JS 调用:

const sayHello = () => console.log("hello");
btn.addEventListener("click",undefined);

考虑到这一点,当您添加事件侦听器时会调用您的 btn.addEventListener("click",sayHello); 参数,这意味着 throttleFunction() 本身并不是作为第二个参数传递给 {{1 }},而是返回值。如果您将回调提取到 throttleFunction,这可能会更清楚一些:

addEventListener()

由于您的函数正在被调用,因此 throttleFunction 返回的函数被用作 const fn = () => {console.log("button is clicked")}; // invoking the function ------------\/ const clickHandler = throttleFunction(fn,1500); btn.addEventListener("click",clickHandler); // clickHandler is a reference to a function (a non-invoked/called function) 的参数,而不是 ThrottleFunction 本身。返回的函数只有在发生点击时才会执行。因此,throttleFunction 在第一次调用 ThrottleFunction 时执行一次,也就是添加点击事件监听器时,但返回的函数会执行多次,因为 JS 只会在您点击按钮时调用它。