2016-11-08 63 views
1

我不知道如何解釋下面的代碼,爲什麼按預期不起作用:的setTimeout回調Explination

for (var i = 0; i < 16; i++) { 

    setTimeout(function() { 
     console.log(i); 
    }, 1) 

} 

// Prints "16" 16 times 

一個解決方案,這將被簡單地使用let代替var在for循環,或者

for (var i = 0; i < 16; i++) { 

    (function (k) { 
     setTimeout(function() { 
      console.log(k); 
     }, 100) 
    })(i) 
} 

// Print "0" to "15" 

自我調用功能。

如果我可以有一個有教養的猜測這將是var的範圍綁定到功能塊,或在全球範圍的情況下,for循環將擊敗調用堆棧,setTimeout()將產生和自Javascript是詞彙的作用域,它回調所有這些功能爲var i = 16另一方面let i = 16將保持它的塊?

+0

'setTimeout'在* i循環後執行* – Li357

+0

請參閱[如何閉包](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Rajesh

回答

0

在第一個示例中,圍繞循環變量i進行閉合。在第二種情況下,您通過複製i而不是使用k來避免這種情況。避免關閉允許每次迭代保持其自己的值,而不是與所有迭代共享i。使用let也可以解決這個問題,因爲它會使循環變量i具有塊級作用域,這意味着在每次迭代時,i在技術上都會是一個與前一個不同的變量,因此每個嵌套函數都會獲得一個引用以不同的價值。

這都是因爲JavaScript的工作原理以及嵌套函數如何導致閉包,當嵌套函數引用來自高階函數的變量時嵌入函數具有副作用,並且嵌套函數的壽命比家長。在你的情況下,由setTimeout引用的功能將比其包含的功能壽命更長。