我有以下代码。在这里,我尝试将单击事件处理程序添加到页面上的按钮。 以下代码不起作用,并将输出显示为"[对象 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 对象,如果你愿意在你的函数中使用它。