Javascript Closure事件处理程序问题

时间:2017-03-13 06:47:39

标签: javascript

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

<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

document.addEventListener('DOMContentLoaded', function() {
 var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
for (var btnNum = 0; btnNum < prizes.length; btnNum++) {
debugger;
    // for each of our buttons, when the user clicks it...
    document.getElementById('btn-' + btnNum).onclick = function(btnNum) {

        var btnNum1=btnNum;

        alert(btnNum1);
    };

}   

});

2 个答案:

答案 0 :(得分:0)

代码应为

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

显然奇怪的模式的原因

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

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

更新的Javascript let允许创建局部变量而无需使用此function + (return function)模式。

使用let代码,例如

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

将按预期工作。

答案 1 :(得分:0)

从函数的参数列表中删除btnNum,闭包将按照预期(在.onclick = function(btnNum) {…中)工作,并提及警告6502(它是&#39}在每个闭包中共享相同的变量,因此它将是相同的值。)

闭包的关键是你在该范围内定义的函数中使用外部作用域的局部变量。当你这样做时:

whatever.onclick = function(btnNum) {

    var btnNum1=btnNum;

    alert(btnNum1);
};

您将btnNum声明为函数的参数,这意味着它是一个局部变量,您无法从onclick函数外部访问btnNum变量(它自己的btnNum是&#34;阴影&#34;闭包中的那个。)

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

whatever.onclick = function(event) {

    var btnNum1=btnNum;

    alert(btnNum1);
};

标识符&#34; btnNum&#34;无法在onclick函数的范围内解析,因此解释器上升scope chain并找到&#34; btnNum&#34;外部函数范围内的变量。我重命名为event的参数仍然是一个Event对象,如果你在你的函数中使用它。