我有以下小代码片段,其中包含以下预期和实际输出。我的问题很简单。为什么按顺序打印呢?以及如何打印预期的输出?
GR,
预期结果:
0
1
2
0
1
2
真实结果:
0
1
2
3
3
3
这是代码:
var functions = [];
for (var i=0; i<10; i++) {
console.log (i);
functions.push (function () {
console.log (i);
});
};
for (var j=0; j<functions.length; j++) {
functions[j] ();
};
答案 0 :(得分:5)
您推入数组的函数不会像创建函数时那样记录i
的值,它们会在调用函数时记录i
的值
第一个循环结束后,i
的值为10
,因此之后调用的任何函数都会记录值10
。
如果要在不同状态保留i
的值,可以使用闭包来复制值:
for (var i=0; i<10; i++) {
console.log (i);
(function(){
var copy = i;
functions.push (function () {
console.log (copy);
});
})();
};
局部变量copy
将获得i
的值并保留该值。您还可以将值作为参数传递给函数:
for (var i=0; i<10; i++) {
console.log (i);
(function(copy){
functions.push (function () {
console.log (copy);
});
})(i);
};
答案 1 :(得分:2)
预期结果应为:
1
2
...
10
10
10
... 7 more times
原因很简单。循环中的console.log(i)
在循环的每次迭代中正确打印i
的值。当您将函数创建并推送到functions
数组时,您正在做的是在同一变量i
上关闭每个函数。在循环结束时,i
不再满足您的循环条件,因此i = 10
为真。因此,由于这些函数中的每一个都将执行console.log(i)
,并且每个函数都在相同的i
上关闭,现在它的值为10,您应该会看到值10打印10次。
为了防止这种情况,你需要创建一个函数来返回一个函数,而不是直接在循环中创建函数:
var functions = [], i, j;
function createEmitter(i) {
return function () {
console.log(i);
};
}
for (i = 0; i < 10; i++) {
console.log(i);
functions.push(createEmitter(i));
};
for (j = 0; j < functions.length; j++) {
functions[j]();
};
现在,每个创建的函数都关闭在它自己的私有范围变量上,这可以解决问题。
答案 2 :(得分:0)
您应该将您的代码示例更新为i&lt; 3,以便您的结果和功能匹配。
你推入functions
数组的函数是存储对变量i的引用,在执行top循环之后,它是10.因此当它执行时,它将获得变量i(即10)并打印10次。
这是一个很好的方式来看到这个:
for (var i=0; i<10; i++) {
console.log (i);
};
console.log(i) //=> 10
当你使用变量时,记住变量可以改变,它不会冻结它的当前值。你只是坚持引用别的东西。
要解决这个问题,我会在代码上运行这种类型的次要重构(因为其他答案已经创建了一个额外的范围,我想你会给你一些不同的东西)。而不是存储10个函数,只需存储数字并使用单个函数执行它们。无论如何,这是一种更优雅的写入方式,占用的空间更少。我确信这个例子是从任何真正给你问题的代码中抽象出来的,但是一般模式仍然适用。
numbers = [];
for (var i=0; i<10; i++) {
console.log (i);
numbers.push(i);
};
numbers.forEach(function(i){
console.log(i);
});