事实上,这种情况很容易解释,它出现在许多编程语言中,而不仅仅是 JavaScript。
让我们首先获取输出序列a,b,c,c,c,c并丢弃前三个元素 -a,b,c因为这是f()在第一个for循环中执行函数时打印的内容。
c,c,c所以,当我们遍历fs数组时,我们留下了打印出来的序列。你没有被a,b,c打印出来的原因是x你在你的第一个for循环中的参数是由你的闭包通过引用捕获的(虽然不确定定义是否有效)f()(记住,JavaScript中的每个函数都是一些闭包种类)。
现在,由于在console.log(x)调用 时计算表达式,因此捕获的参数f()的当前值x将作为参数传递。虽然代码可以正常工作,但正如预期的那样,当您f()在第一个for循环中调用时,这x是刚刚分配的内容,arr[i]因此您得到a,b,c. 但是当你退出循环时,x(即使它对外部范围不可用)仍然被捕获,f()但在第一个循环之后它有一个值c(它在最后一次迭代中得到的那个),这就是你在第二次迭代你的函数。
事实上,这可能是许多令人困惑的错误的根源,因此某些语言可以检测到这一点并通知开发人员(例如,C# 编译器,当它看到这样的结构时,会产生以下警告:)Access to modified closure。
要解决此问题,您只需要捕获第一个循环内的当前值:xfor
for (var i in arr) {
var x = arr[i];
var f = (function(x) {
return function() { console.log(x) };
})(x);
f();
fs.push(f);
}
这里我们使用 IIFE(立即调用函数表达式)来捕获x.
希望这可以帮助。