如何在闭包中'取消'变量?

时间:2013-09-18 10:18:15

标签: javascript closures

我正在尝试使用规则对象添加事件侦听器,例如

keyMap = [
    {name: "Up", type: "keydown", code: 87, action: function(){alert("up")}},
    {name: "Down", type: "keydown", code: 83, action: function(){alert("down")}},
    {name: "Left", type: "keydown", code: 65, action: function(){alert("left")}},
    {name: "Right", type: "keydown", code: 68, action: function(){alert("right")}}
]

for(var keyAct of keyMap){
    if( typeof keyAct.action === "function" ){
         document.addEventListener(keyAct.type, function(e){
            if(e.keyCode === keyAct.code){
                keyAct.action(e);
            }
         });
    }
}

然后w / a / s / d按下所有警告“右”。我重写了for这样的部分:

for(var keyAct of keyMap){
    (function(keyAct){
        if( typeof keyAct.action === "function" ){
             document.addEventListener(keyAct.type, function(e){
                if(e.keyCode === keyAct.code){
                    keyAct.action(e);
                }
             });
        }
    })(keyAct);
}

它有效,但这是唯一的方法吗?我能更优雅地做到吗?我的意思是,这看起来很奇怪。

2 个答案:

答案 0 :(得分:1)

创建另一个绑定事件的函数,试试这个:

for(var i = 0, len = keyMap.length; i < len; ++i) {
    if( typeof keyMap[i].action === "function" ) {
        binder(keyMap[i]);
    }
}

function binder(keyAct) {
    document.addEventListener(keyAct.type, function(e) {
        if(e.keyCode === keyAct.code) {
            keyAct.action(e);
        }
    });
}

答案 1 :(得分:0)

我总是将这样的构建器函数分开,以避免不必要地重新构建构建器函数并且为了清晰起见:

for(var keyAct of keyMap){
    if( typeof keyAct.action === "function" ){
         document.addEventListener(keyAct.type, buildHandler(keyAct));
    }
}

// Elsewhere
function buildHandler(keyAct){
    return function(e) {
        if(e.keyCode === keyAct.code){
            keyAct.action(e);
        }
    };
}

旁注:for-in循环不是为循环数组条目而设计的,它们用于循环遍历对象的可枚举属性。在数组上使用它们往往会让你遇到麻烦(如果你曾经直接或通过扩展Array.prototype向数组中添加了可枚举的非索引属性)。详情:Myths and realities of for..in