簡體   English   中英

為什么在setTimeout函數中看不到for循環中定義的變量?

[英]Why isn't a variable defined in for loop not visible in setTimeout function?

當我在控制台中運行以下代碼時:

for(var k = 0; k < 36; k++){
    setTimeout(function(k){ alert(k)}, k*5000);
}

警報顯示未定義。 而且,我希望每次迭代后超時功能的延遲都會增加; 但這不會發生。 超時功能應首先在5秒后運行,然后在10秒后再運行15秒,依此類推。

為什么未定義的警報會發出警報,為什么每次迭代后延遲都不會增加?

由於k在超時功能的本地范圍內,因此它應該在其中可見。

它是undefined因為計時器機制setTimeout會將函數掛接到該函數,而不會調用帶有任何參數的函數(默認情況下),並且已將k聲明為函數參數。 當您調用的JavaScript函數的參數少於其聲明的參數時,這些參數的值是undefined 因此, 參數 k遮蔽(隱藏) 循環變量 k ,您始終會看到undefined

要解決此問題,請不要將k聲明為函數參數:

for (var k = 0; k < 36; k++){
    setTimeout(function(){ alert(k)}, k*5000);
    // No k here -------^
}

示例(使用500代替5000):

 for (var k = 0; k < 36; k++){ setTimeout(function(){ console.log(k)}, k*500); // No k here -------^ } 

但是 ,則您必須修復一個新問題( 此問題及其答案解決的問題 ):所有這些回調看到的k的值將相同 (36),因為它們將k的值視為何時調用它們(后來,一旦循環結束),而不是何時創建它們。

在ES5及更早版本中,我將這樣解決:

function createHandler(k) {
    return function(){ alert(k)};
}
for (var k = 0; k < 36; k++){
    setTimeout(createHandler(k), k*5000);
}

例:

 function createHandler(k) { return function(){ console.log(k)}; } for (var k = 0; k < 36; k++){ setTimeout(createHandler(k), k*500); } 

...盡管許多人會在循環中重復創建該createHandler函數:

for (var k = 0; k < 36; k++){
    setTimeout(function(innerk) {
        return function() { alert(innerk); }
    }(k), k*5000);
}

例:

 for (var k = 0; k < 36; k++){ setTimeout(function(innerk) { return function() { console.log(innerk); } }(k), k*500); } 

在ES2015 +(“ ES6”及更高版本)中,我會這樣解決:

for (let k = 0; k < 36; k++){
    setTimeout(() => { alert(k); }, k*5000);
}

...因為在諸如此類的for使用let時,它將為每次迭代創建一個新的k ,其值保持不變。

例:

 // REQUIRES ES2015+ SUPPORT for (let k = 0; k < 36; k++){ setTimeout(() => { console.log(k); }, k*500); } 

您可以通過兩種方式傳遞k參數:

for(var k = 0; k < 36; k++){
    setTimeout(function(k){ alert(k); }, k * 5000, k); // but is not supported in IE9 and earlier
}

或更好地將其包裝到一個函數調用中:

for (var k = 0; k < 36; k++) _setTimeout(k);

function _setTimeout(k) {
    setTimeout(function(){ alert(k); }, k * 5000);
}

您可以將k傳遞給setTimeOut的回調函數,但它什么也不做。因此刪除參數k即可。

for(var k = 0; k < 36; k++){
setTimeout(function(){ alert(k)}, k*5000);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM