Javascript 闭包事件处理程序问题



我有以下代码。在这里,我尝试将单击事件处理程序添加到页面上的按钮。 以下代码不起作用,并将输出显示为"[对象 MoustEvent]"。我知道如何修复它(使用另一个闭包并围绕它包装 onclick 处理程序),但我想了解为什么我会得到这个输出。 有人可以解释一下吗?

document.addEventListener('DOMContentLoaded', function() {
var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
for (var btnNum = 0; btnNum < prizes.length; btnNum++) {

// for each of our buttons, when the user clicks it...
document.getElementById('btn-' + btnNum).onclick = function(btnNum) {
var btnNum1 = btnNum;
alert(btnNum1);
};
}
});
<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

代码应该是

document.getElementById('btn-' + btnNum).onclick = (function(btnNum){
return function(){
var btnNum1=btnNum;
alert(btnNum1);
}
})(btnNum);

明显奇怪的模式的原因

(function(x){ return function(){ ... } })(x);

这是因为在(旧的)Javascript中,局部变量具有函数作用域,而不是块作用域;创建新变量以捕获的唯一方法是使用(可能是嵌套的)函数。

最近的Javascriptlet允许创建局部变量而不必使用此function + (return function)模式。

使用let代码,例如

for (let btnNum = 0; btnNum < prizes.length; btnNum++) {
document.getElementById('btn-' + btnNum).onclick = function() {
var btnNum1=btnNum;
alert(btnNum1);
};
}

将按您的预期工作。

从函数的参数列表中删除btnNum,闭包将

按预期工作(以.onclick = function(btnNum) {…为单位),并提及警告 6502(它是每个闭包中共享的相同变量,因此它将是相同的值)。

闭包的要点是,您可以在该作用域中定义的函数中使用外部作用域中的局部变量。当您执行以下操作时:

whatever.onclick = function(btnNum) {
var btnNum1=btnNum;
alert(btnNum1);
};

您将btnNum声明为函数的参数,这意味着它是一个局部变量,您无法从 OnClick 函数外部访问btnNum变量(它自己的btnNum正在"隐藏"闭包中的变量)。

由于onclick是一个偶数处理程序,因此传递给它的第一个参数是一个事件,并且您声明此参数应称为btnNum。所以你来了。另一方面,有了这个:

whatever.onclick = function(event) {
var btnNum1=btnNum;
alert(btnNum1);
};

标识符 "btnNum" 无法在 onclick 函数的作用域中解析,因此解释器沿作用域链向上移动,并在外部函数的作用域中找到 "btnNum" 变量。我重命名为event的参数仍然是一个 Event 对象,如果你愿意在你的函数中使用它。

最新更新