带有闭包的循环应该可以解决问题:
for (var i = 0; i <= 9; ++i) {
(function(i) { // Capture current value of 'i' in this scope.
shortcut.add(i.toString(), function() {
points = i || -1; // 'i' if 'i' is not 0, else -1.
sec = 0;
});
})(i);
}
更新以下评论:那么为什么我们需要在这里关闭?最后是什么(i);
意思?
基本上,我们需要一个闭包,因为传递给的匿名函数shortcut.add()
不会立即被调用,而是在未来某个时间,在循环终止之后。i
函数通过引用而不是值捕获,这意味着它们将在运行时i
看到当前的值,而不是在定义时。
因此,如果我们shortcut.add()
直接从循环体中调用,我们传递的所有匿名函数最终都会i
在循环终止后看到当前的值,这将始终是相同的 ( 10
)。
在每次迭代中创建一个新变量看起来可以工作,但没有:
for (var i = 0; i <= 9; ++i) {
var _i = i; // Create new variable containing current value of 'i'.
shortcut.add(i.toString(), function() {
points = _i || -1; // Won't work, '_i' is always 9.
sec = 0;
});
}
由于for
循环体在 Javascript 中没有自己的作用域,_i
因此在函数作用域中结束,与 , 相同i
,并将以相同的方式捕获(其最终值将9
代替,10
因为++i
不适用于它)。
所以,我们真正需要的是在每次迭代中都有一个新的作用域。为此,我们可以在循环中定义一个函数,并立即调用它,并将当前值传递给它i
:
var newScope = function(i) {
// Here, the value of 'i' will be the one current when 'newScope' is called
// and will not change, even if 'i' is captured by other functions.
};
newScope(i); // Call function with current value of 'i'.
最后,我们可以在不引入newScope
名称的情况下直接将调用运算符()
应用于函数定义:
(function(i) {
// Here, the value of 'i' will be the one current when this function is
// called and will not change, even if 'i' is captured by other functions.
})(i); // Call function with current value of 'i'.
我希望这能适当地回答您的问题,如果没有,请随时留下进一步的评论。有关闭包的更多信息,请参阅MDN 上的闭包。