This question already has answers here:
JavaScript closure inside loops – simple practical example
(44个回答)
3年前关闭。
我正在构建一个基于JavaScript的游戏,并在地图上划分了区域。对于每个地区,游戏都会检查某些条件,如果满足,则将单击功能添加到该地区。这将导致以下代码:
由于某些原因,第一个控制台日志按预期报告变量“ ter”。但是,一旦通过单击相应的区域记录了完全相同的ter,就会返回未定义的值。我的第一个想法是,ter的值将在我单击区域时(在循环结束后且变量不再存在之后)确定,而不是在创建click函数时确定其值。但是,在我看来这不太可能,因为我还有另一段代码可以像这样工作,但是没有给出未定义的值。下面是一个示例:
有人能弄清楚为什么这个变量按原样运行以及如何解决吗?
先感谢您!
对此:
将代码包装在IIFE(立即调用的函数表达式)中将为每次迭代创建新的作用域。外部
(44个回答)
3年前关闭。
我正在构建一个基于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]);
}
}
}
有人能弄清楚为什么这个变量按原样运行以及如何解决吗?
先感谢您!
最佳答案
更改此:
$('#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(立即调用的函数表达式)中将为每次迭代创建新的作用域。外部
ter
传递给IIFE,以将其设置为内部ter
,该内部ter
在定义事件侦听器功能的范围内是唯一的。在您的代码中,所有事件侦听器都将引用相同的for
,然后使用territoryStateInfo.length
循环对其进行递增,直到它变为ter
,因此,当发生单击时,事件侦听器内部的将成为长度,无论单击什么按钮=> for循环都会使闭包混乱,因为它在整个迭代过程中都具有相同的作用域,因此,取决于该作用域的所有函数都将引用在该作用域内创建的相同变量(该作用域for循环所在的函数),最糟糕的是,原始作用域中的那些变量一直在变化(即使在循环之后)。07-24 15:37