我正在构建一个简单的计算器应用程序。我正在尝试完成三件事:
将事件侦听器分配给按钮。
单击该按钮时,触发一个事件。
使用eventListener函数显示单击按钮的值。
for (i = 0; i < btn.length; i++) {
var btnVal = btn[i].value;
btn[i].addEventListener("click", function() { displayNumber(btnVal) }, false);
}
function displayNumber(param) {
displayedNum.innerHTML = param;
}
传递给事件侦听器函数时,似乎无法访问btnVal。
最佳答案
在循环内定义事件监听器(或其他异步事物)非常棘手。您可能会认为您正在创建几个不同的btnVal
变量,每次在循环中都创建一个变量,但事实并非如此。该var btnVal被吊起并重新使用,因此您的代码最终表现如下:
var btnVal;
for (i = 0; i < btn.length; i++) {
btnVal = btn[i].value;
btn[i].addEventListener("click", function() { displayNumber(btnVal) }, false);
}
因此,所有事件侦听器都与同一个变量进行交互,并且当最终单击它们时,他们将仅看到分配给btnVal的最后一个值,该值应为
btn[btn.length -1].value
。数组前面的所有值都将丢失。有几种方法可以解决此问题:
1)您可以在事件结束时将其从元素本身中拉出,而不是依赖于闭包变量。
for (i = 0; i < btn.length; i++) {
btn[i].addEventListener("click", function (event) {
displayNumber(event.target.value);
});
}
2)将事件侦听器的创建移到一个函数中,并传入btnVal。由于它现在是一个函数参数,因此它将获得一个新的绑定。
for (i = 0; i < btn.length; i++) {
createListener(btn[i], btn[i].value);
}
function createListener(element, val) {
element.addEventListener("click", function () { displayNumber(val) }, false);
}
3)您可以使用IIFE内联。
for (i = 0; i < btn.length; i++) {
(function (button) {
button.addEventListener("click", function () { displayNumber(button.value) }, false);
})(btn[i]);
}
编辑:添加选项4
4)如果可以使用ES2015,请使用
let
。 Let具有块作用域,并且每次通过循环都会获得一个新的绑定for (i = 0; i < btn.length; i++) {
let btnVal = btn[i].value;
btn[i].addEventListener("click", function() { displayNumber(btnVal) }, false);
}