考虑这个经典的Javacrit闭包函数。我理解封闭是如何展示的。我理解内部函数关闭变量i,即3。
我不明白为什么数组应该包含变量i,当我们所做的就是将一个函数推入一个数组,其中我有一个来自for循环的值。
function buildFunctions() {
var arr = [];
for (var i = 0; i < 3; i++) {
arr.push(function() {
console.log(i)
})
}
return arr;
}
var fs = buildFunctions(); // [function(){console.log(1)}, ...and so on]
//not [function(){console.log(i)} ...and so on]
fs[0](); // outputs 3
fs[1](); // 3
fs[2](); // 3
否则,这将返回数组的正确(imo)内容:
function buildFunctions() {
var arr = [];
for (var i = 0; i < 3; i++) {
arr.push(i)
}
return arr; // [0, 1, 2]
}
答案 0 :(得分:3)
arr.push(i)
分别将原始值传递给.push
,值0
,1
和2
。该值与此处i
取消关联;你没有推i
,而是推动0
,1
和2
。
arr.push(function () { console.log(i) })
推送一个函数,该函数在内部引用变量。在调用函数时,该变量的值恰好是3
。 (这是要理解的重要句子。)
请注意,推送功能和推送数字之间没有根本区别。两者都是按价值传递的。在一种情况下,值是一个数字,在另一种情况下,值是一个函数。请参阅Is JavaScript a pass-by-reference or pass-by-value language?。
答案 1 :(得分:2)
我认为循环因某种原因增加了混乱。如果您展开该循环,它可能更直观。
function buildFunctions() {
var arr = [];
var i = 0;
arr.push(function() {
console.log(i)
})
i++;
arr.push(function() {
console.log(i)
})
i++;
arr.push(function() {
console.log(i)
})
i++;
return arr;
}
var fs = buildFunctions(); // [function(){console.log(1)}, ...and so on]
//not [function(){console.log(i)} ...and so on]
fs[0](); // outputs 3
fs[1](); // 3
fs[2](); // 3
&#13;
所以你可以看到我们将三个函数推入数组,在两者之间,我们正在递增i
。你还可以看到所有三个功能都是&#34;看着&#34;相同的i
变量。
在调用函数之前不会读取变量 ,因为它们全部&#34;查看&#34;相同的变量,它们在最终调用时自然会产生相同的结果。由于i
在任何调用之前增加了三次,因此返回的值将为3
。
作为练习,更改每个功能以在其中添加另一个i++
。您会发现他们不仅正在阅读相同的变量,而且他们也可以改变同一个变量。
答案 2 :(得分:1)
当您调用该函数时,i
的值变为3
arr.push
中的函数引用。
阻止范围let
将为您提供预期的结果:
function buildFunctions() {
var arr = [];
for (let i = 0; i < 3; i++) {
arr.push(function() {
console.log(i)
})
}
return arr;
}
var fs = buildFunctions(); // [function(){console.log(1)}, ...and so on]
//not [function(){console.log(i)} ...and so on]
fs[0](); // 0
fs[1](); // 1
fs[2](); // 2
&#13;
答案 3 :(得分:1)
我不明白为什么数组应该包含变量i
它没有。
该数组包含三个函数。
每个函数都关闭(相同)变量i
。注意:i
当时不是 i
的值。
当调用任何函数(循环完成后 )时,它们会读取该变量的值。