2017-06-16 112 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); 
} 

這將產生預期的結果。

相關問題