javascript闭包为什么我得到var undefined

时间:2017-06-16 23:43:53

标签: javascript closures

我运行以下两个代码段。

当我为局部变量指定不同的名称时,第一个循环给出了预期的结果。



for(var i = 0; i < 3; i++) {
    setTimeout((function() {
    	var i2 = i;//named i2 here
        return function(){console.log(i2)};
    })(), 10);
}
&#13;
&#13;
&#13;

第二个循环将打印undefined。我想 var i = i将重新声明原始i。而且我希望它可以提供一些数字。 为什么我在这里得到不确定?

&#13;
&#13;
for(var i = 0; i < 3; i++) {
    setTimeout((function() {
    	var i = i;
        console.log(i);
        return function(){console.log(i)};
    })(), 10);
}
&#13;
&#13;
&#13;

4 个答案:

答案 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

时使用i
for(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'

将产生预期的结果。