为什么我的闭包在我使用 addEventListener 方法时有效,但没有使用 onclick HTML 属性

Why Is My Closure working when I use the addEventListener method, but not with the onclick HTML attribute

我尝试让一个按钮只被点击一次。

var user, sales, data;

function getBill(user, sales, data) {
    window.alert("Here is your bill.");
    //do the billing process
}

const once = fn => {
    let finished = false;
    return (...args) => {
        if (!finished) {
            finished = true;
            fn(...args);
        }
    };
};

当我将此 HTML 与 onclick 一起使用时。每次我点击按钮时按钮都会提醒,因为它进入一次并将“完成”设置回 false。

<button id="billButton" onclick="once(getBill)(user,sales,data)">Pay Order</button>

但是,移除onclick属性并使用“addEventListener”方法使得该按钮只能点击一次。

document.getElementById("billButton").addEventListener('click' ,once(getBill)(user, sales, data));

它是怎么来的,如何使用“onclick”属性?我知道属性侦听器是不好的做法,但这不是术语。它应该可以正常工作。

我错过了什么?

您没有正确使用 addEventListener,因为您没有添加事件。 另一个建议是做我所做的,所以点击按钮启动你的功能,然后用没有 EventListener 的新按钮替换旧按钮,比如:

const user = 'simon',
  sales = '1',
  data = 'today',
  button = document.getElementById("billButton");

function getBill(user, sales, data) {
  //tips add load here
  window.alert("Here is your bill."); 
  //on finish stop loader
}

button.addEventListener('click', () => {
  getBill(user, sales, data);
  let buttonClone = button.cloneNode(true); // create clone html (don't clone the event)
  button.parentNode.replaceChild(buttonClone, button); // replace it
  buttonClone.disabled = true; //disable button
});
<button id="billButton">Pay Order</button>

首先,让我们看看HTML中的onclick属性是如何工作的:

  1. 它只会以纯文本形式存储函数调用语句。
  2. 当您单击该元素时,它会检查 onclick 属性中是否有任何内容。
  3. 如果onclick属性中有任何东西,它只会用eval执行它。

回到你的代码,每当你点击按钮时,它总是会显示警报,因为它每次都会调用一个新函数,它不会存储 return 从 [=20] 编辑的函数=].

var user, sales, data;

function getBill(user, sales, data) {
  window.alert("Here is your bill.");
}

const once = fn => {
  let finished = false;
  return (...args) => {
    if (!finished) {
      finished = true;
      fn(...args);
    }
  };
};
<button id="billButton" onclick="once(getBill)(user,sales,data)">Pay Order</button>

现在,让我们看看 eventListener 是如何工作的:

  1. EventListeners 将函数引用绑定到事件。
  2. 因此,每当该特定事件发出时,它都会调用绑定到它的函数。

再次回到您的代码,您没有将函数绑定到 eventListener,而是将函数的 return 值绑定到事件,在本例中为 undefined.

绑定高阶函数响应的正确方法是,使用bind,是:

document.getElementById("billButton").addEventListener('click' ,once(getBill).bind(this, user, sales, data));

var user, sales, data;

function getBill(user, sales, data) {
  window.alert("Here is your bill.");
}

const once = fn => {
  let finished = false;
  return (...args) => {
    if (!finished) {
      finished = true;
      fn(...args);
    }
  };
};

document.getElementById("billButton").addEventListener('click', once(getBill).bind(this, user, sales, data));
<button id="billButton">Pay Order</button>