2017-06-16 113 views
1

我运行以下两个代码片段。javascript closure为什么我得到var undefined

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

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

第二个循环将打印,而不是不确定的。我以为 var i =我会重新声明原来的i。我期望它提出一些数字。 我怎么在这里弄不明白?

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

回答

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

范围

var i声明了一个已经有一个名为i变量的范围内,所谓i新变量。

的声明分配的值范围最突出的i,这是你刚才声明的一个。

由于新申报的i的值为undefined,因此其本身的赋值为其值undefined

1

变量i已被循环用于外部范围。现在你声明一个新的变量i在内部范围

var 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

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

我的猜测是,应该在第二个片段。而它仍然不起作用的原因是,你基本上将var i分配给你刚刚用var声明的i。你会明白我的意思,如果你拆分的声明和赋值:

var i; 
i = i; 

但是,是的,我可以看到JS怪癖一样,也可以是非常令人沮丧,因为人们必须始终注意和重塑新的变量名称一个进入调用栈。这就是为什么我爱上TypeScript,因为它编译此:

for (let i = 0; i < 3; ++i) { 
    window.setTimeout(() => { 
     console.log(i); 
    }); 
} 

到这一点:

var _loop_1 = function (i) { 
    window.setTimeout(function() { 
     console.log(i); 
    }); 
}; 
for (var i = 0; i < 3; ++i) { 
    _loop_1(i); 
} 

这将产生预期的结果。

相关问题