事实上,这种情况很容易解释,它出现在许多编程语言中,而不仅仅是 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
。
要解决此问题,您只需要捕获第一个循环内的当前值:x
for
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
.
希望这可以帮助。