我正在构建一个基于 javascript 的游戏,其 map 分为多个区域。对于每个区域,游戏都会检查某些条件,如果满足这些条件,则会向该区域添加点击功能。这会产生以下代码:
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 的值将在我单击区域时确定(即循环结束且变量不再存在之后),而不是创建单击函数时的值。然而,在我看来这不太可能,因为我有另一段代码的工作原理与此类似,但没有给出未定义的值。示例如下:
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]);
}
}
}
有人能弄清楚为什么这个变量会这样起作用以及我该如何解决这个问题吗? 预先感谢您!
最佳答案
更改此:
$('#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中(I立即I调用F函数Expression) 将为每次迭代创建一个新的范围。外部 ter
被传递到 IIFE 以将其设置为内部 ter
,该内部 ter
在定义事件监听器函数的范围内是唯一的。在您的代码中,所有事件监听器都将引用相同的 ter
,然后使用 for
循环递增该引用,直到它变为 territoryStateInfo.length
,因此当单击发生时,无论单击哪个按钮,事件监听器内的 ter
都将是长度 => for 循环会弄乱闭包,因为它在整个事件中保持相同的范围整个迭代,因此依赖于该作用域的所有函数都将引用在该作用域(for 循环所在函数的作用域)内创建的相同变量,最糟糕的是原始作用域中的这些变量不断变化(即使在循环之后)。
关于javascript - click 函数中的 var 变得未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42847045/