单击函数中的var变为未定义

时间:2017-03-17 00:16:35

标签: javascript jquery

我正在建立一个基于javascript的游戏,地图分为地区。对于每个区域,游戏会检查某些条件,如果符合这些条件,则会向该区域添加点击功能。这导致以下代码:

for (var ter = 0; ter < territoryStateInfo.length; ter++) {
    for (var adjacent = 0; adjacent < territoryStateInfo[ter].adjacentTer.length; adjacent++) {
        var tempAdjID = territoryStateInfo[ter].adjacentTer[adjacent];
        if (/*long if statement*/) {
            console.log(ter);
            $('#territoryArea' + ter).addClass('viableTarget');
            $('#territoryArea' + ter).click(function(){
                console.log(ter);
                applyNH(ter);
                for (var ter = 0; ter < territoryStateInfo.length; ter++) {
                    $('#territoryArea' + ter).removeClass('viableTarget');
                }
            });
            break;
        }
    }
}

出于某种原因,第一个控制台日志按预期报告变量“ter”。但是,只要通过单击相应的区域记录完全相同的ter,它就会返回未定义的值。我的第一个想法是ter的值将在我点击区域(在循环结束并且变量不再存在之后)而不是在创建click函数时的值时确定。然而,这似乎不太可能,因为我有另一段代码可以像这样工作,但不提供未定义的值。一个例子如下:

var viableUtilityTargets = [];
for (var ter = 0; ter < territoryStateInfo.length; ter++) {
    for (var unit = 0; unit < territoryStateInfo[ter].occupiedByUnits.length; unit++) {
        if (/*another long ramble*/) {
            if ($('#territoryArea' + ter).hasClass !== 'viableTarget') {
                $('#territoryArea' + ter).addClass('viableTarget');
                $('#territoryArea' + ter).click(function(){
                    console.log(ter);
                    applyUtility(ter, viableUtilityTargets);
                });
            }
            viableUtilityTargets.push(territoryStateInfo[ter].occupiedByUnits[unit]);
        }
    }
}

任何人都可以弄清楚为什么这个变量的行为方式以及如何解决这个问题? 提前谢谢!

1 个答案:

答案 0 :(得分:0)

改变这个:

$('#territoryArea' + ter).click(function(){
    console.log(ter);
    applyUtility(ter, viableUtilityTargets);
});

到此:

$('#territoryArea' + ter).click(
    (function(ter){
        return function() {
            console.log(ter);
            applyUtility(ter, viableUtilityTargets);
        };
    })(ter)
);

将代码包含在 IIFE 中(立即 nvoked F 正在 E xpression)将为每次迭代创建一个新范围。外部ter将传递给 IIFE ,以将其设置为内部ter,这在定义事件侦听器功能的范围内将是唯一的。在您的代码中,所有事件侦听器都将引用相同的ter,然后使用for循环递增,直到它变为territoryStateInfo.length,因此当单击发生时{{1}无论点击什么按钮,事件监听器内部都将是长度=&gt; for循环弄乱了闭包,因为它在整个迭代中保持相同的范围,因此所有依赖于该范围的函数都将引用在该范围内创建的相同变量(函数的范围为for循环是),最糟糕的是原始范围内的变量不断变化(即使在循环之后)