为什么这个节流函数中的事件监听器会这样?

why does the event listener in this throttling function behave like that?

当我学习 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() 运行并 returns undefined

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

sayHello() 上方是一个函数调用,因此它将在添加事件侦听器时以及在发生任何点击之前执行,从而导致使用 sayHello 的 return 值作为 addEventListener() 的第二个参数,所以上面的代码将计算如下:

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

要正确传递对事件侦听器的引用,您需要传递一个函数,该函数稍后可以在发生点击时由 JS 调用:

btn.addEventListener("click", sayHello);

考虑到这一点,当您添加事件侦听器时会调用您的 throttleFunction() 参数,这意味着 throttleFunction 本身并不是作为第二个参数传递给 addEventListener(),而是 return 值。如果将回调提取到 throttleFunction:

,这可能会更清楚一些
const fn = () => {console.log("button is clicked")};
// invoking the `throttleFunction` function with `()`
const clickHandler = throttleFunction(fn, 1500);
btn.addEventListener("click", clickHandler); // clickHandler is a reference to a function (a non-invoked/called function)

由于正在调用您的 throttleFunction() 函数,throttleFunction 中的 returned 函数被用作 addEventListener() 的参数,而不是 throttleFunction 本身。 returned 函数只有在点击发生时才会执行。结果,let prev = 0;在第一次调用throttleFunction时执行一次,也就是添加点击事件监听时,但是returned函数执行了多次,因为JS只有在点击时才会调用它在你的按钮上。