我运行以下两个代码段。
当我为局部变量指定不同的名称时,第一个循环给出了预期的结果。
for(var i = 0; i < 3; i++) {
setTimeout((function() {
var i2 = i;//named i2 here
return function(){console.log(i2)};
})(), 10);
}
&#13;
第二个循环将打印undefined。我想 var i = i将重新声明原始i。而且我希望它可以提供一些数字。 为什么我在这里得到不确定?
for(var i = 0; i < 3; i++) {
setTimeout((function() {
var i = i;
console.log(i);
return function(){console.log(i)};
})(), 10);
}
&#13;
答案 0 :(得分:2)
var
的初始化表达式的范围是函数的主体,局部变量i
已经在该范围内。因此,您无法引用具有相同名称的外部变量。你可以想到
var x = <expression>;
等同于:
var x;
x = <expression>;
如果你这样看,你可以看到为什么var i = i;
不起作用,它相当于:
var i;
i = i;
赋值使用局部变量的未初始化值。
解决此问题的通常习惯是使i
成为函数的参数,然后将其传递给IIFE的参数列表。
for(var i = 0; i < 3; i++) {
setTimeout((function(i) {
console.log(i);
return function(){console.log(i)};
})(i), 10);
}
有关详细信息,请参阅JavaScript closure inside loops – simple practical example
答案 1 :(得分:1)
内部var i
在已有一个名为i
的变量的范围内声明一个名为i
的新变量。
声明被赋予范围最突出的i
的值,这是你刚宣布的那个。
由于新声明的i
的值为undefined
,因此其自身的分配值为undefined
。
答案 2 :(得分:1)
变量i已被循环用于外部作用域。现在,您在内部范围中声明了一个新变量i
var i = i;
一旦运行了该语句,内部范围就是循环的计数器i更容易访问,因为你用新的i覆盖了它。
基本上你在这里做的是:定义一个新变量i并为其分配一个你刚刚声明的变量值 undefined 。
Eaiset解决方案是声明j并为其赋值i。
for(var i = 0; i < 3; i++) {
setTimeout((function() {
var j = i;
console.log(j);
return function(){console.log(j)};
})(), 10);
}
或者在传递函数setTimeout
时使用ifor(var i = 0; i < 3; i++) {
setTimeout((function(i) {
console.log(i);
return function(){console.log(i)};
})(), 10);
}
答案 3 :(得分:1)
我的猜测是第二个片段中应该是return function(){console.log(i)};
。它仍然不起作用的原因是,您基本上将var i
分配给i
您刚刚用var
声明的var i;
i = i;
。如果你拆分声明和作业,你会明白我的意思:
for (let i = 0; i < 3; ++i) {
window.setTimeout(() => {
console.log(i);
});
}
但是,是的,我可以看到js这样的怪癖是多么令人沮丧,因为当一个人走进调用堆栈时,必须始终注意并重新发明新的变量名。这就是我爱上TypeScript的一个原因,因为它编译了这个:
var _loop_1 = function (i) {
window.setTimeout(function () {
console.log(i);
});
};
for (var i = 0; i < 3; ++i) {
_loop_1(i);
}
进入这个:
user = 'corp\\adam'
将产生预期的结果。