2012-04-18 100 views
4

我想要傳遞變量setTimeout函數並對其進行處理。當我提醒i的價值時,它會顯示我沒有預期的數字。我做錯了什麼?我想記錄從1至值8如何將變量傳遞給匿名函數

var end=8; 
for (var i = 1; i < end; i ++) { 
     setTimeout(function (i) { 
      console.log(i); 

     }, 800); 
    } 
+0

這是正確的?你有什麼錯誤嗎? – Starx 2012-04-18 10:33:52

+1

你的問題是一個範圍問題:'for'計數器變量被稱爲'i',但該參數也稱爲'i'。因此,只要您在參數-i範圍內,計數器i的任何值都會被覆蓋。重命名計數器或參數應該有所幫助。 – 2012-04-18 10:34:15

+0

@DominikSchreiber:這是部分*範圍問題。但只是刪除或重命名'我'參數不會解決它。 – 2012-04-18 10:42:31

回答

-2

setTimeout接受變量作爲附加參數:

setTimeout(function(a, b, c) { 
    console.log(a, b, c); 
    }, 1000, 'a', 'b', 'c'); 

Source

編輯:在你的例子中,i的有效值很可能是8,因爲函數只是在循環完成後調用。你需要傳遞的i的當前值每個呼叫:

var end=8; 
for (var i = 1; i < end; i ++) { 
    setTimeout(function (i) { 
     console.log(i); 
    }, 800, i); 
} 
+1

請記住,雖然「**請注意,在第一種語法中向函數傳遞附加參數在Internet Explorer中無效**」 – 2012-04-18 10:35:10

+0

對於IE,您總是可以使用舊的(但已棄用的)語法:'setTimeout('可調用('+ i +')',1000);'。 – Iso 2012-04-18 10:36:45

+0

這甚至不能在** IE9 **中工作,遠不及早期版本。這個答案在2018年左右的某個時候可能會有用。 – 2012-04-18 10:41:54

11

解決這個標準的方法是使用一個工廠函數:

var end=8; 
for (var i = 1; i < end; i ++) { 
     setTimeout(makeResponder(i), 800); 
    } 

function makeResponder(index) { 
    return function() { 
     console.log(index); 
    }; 
} 

Live example | source

在那裏,我們呼叫makeResponder在循環,並返回其關閉在傳遞給它(index)的說法,而不是i變量的函數。 (這很重要,如果你剛剛從你的匿名函數中刪除了i參數,你的代碼將會部分工作,但是所有函數在運行時看到i的值,而不是當它們最初被調度時;你的榜樣,他們會都看到8


更新從下面您的意見:

... ...它是正確的,如果我以這種方式setTimeout(makeResponder(i),i*800);打電話了嗎?

是的,如果你的目標是讓每個電話大約在800ms出現比上一個後,將工作:

Live example | source

我試圖setTimeout(makeResponder(i),setInterval(i));function setInterval(index) { console.log(index*800); return index*800; }但它無法正常工作

不要使用setInterval這種方式,並且可能不希望在所有使用它的這一點。


進一步更新:你曾經說過如下:

我需要第一次迭代打印8延遲8秒,第二次迭代打印7延遲7秒........打印2延遲2秒...打印0延遲0秒。

你只適用上述原則再次使用第二超時:

var end=8; 
for (var i = 1; i < end; i ++) { 
     setTimeout(makeResponder(i), i * 800); 
    } 

function makeResponder(index) { 
    return function() { 
     var thisStart = new Date(); 
     console.log("index = " + index + ", first function triggered"); 
     setTimeout(function() { 
      console.log("index = " + 
         index + 
         ", second function triggered after a further " + 
         (new Date() - thisStart) + 
         "ms delay"); 
     }, index * 1000); 
    }; 
} 

Live example | source

我想你現在擁有所有需要的工具來推進這項工作。

+0

嗨,謝謝,如果我以這種方式調用setTimeout(makeResponder(i),i * 800),它會是正確的嗎?我的意思是這部分我* 800,我認爲它保持不變。 – alexeyb 2012-04-18 11:02:34

+0

我試過setTimeout(makeResponder(i),setInterval(i)); function setInterval(index){ console.log(index * 800); 返回索引* 800; }但它不能正常工作 – alexeyb 2012-04-18 11:14:30

+0

@alexeyb:我已將答案添加到上面的問題中。 – 2012-04-18 11:34:22

0

這個不能正常工作的主要原因是因爲,其中setTimeout設置爲在800之後運行並且範圍爲i

當它執行時,其值i已經發生了變化。因此沒有收到明確的結果。就像TJ說的那樣,處理這個問題的方法是通過一個處理函數。

function handler(var1) { 
    return function() { 
     console.log(var1); 
    }   
} 

var end = 8; 
for (var i = 1; i < end; i++) {  
    setTimeout(handler(i), 800); 
} 

Demo

1

你的問題是,你指的是可變i一段時間後,當你setTimeout()功能火災,屆時,i值已改變(它去了for結束爲了保持每個setTimeout的值爲i,您必須分別爲每個setTimeout()回調捕獲該值i

上一個使用facto的答案ry函數可以做到這一點,但是我發現自執行函數比工廠函數更容易輸入和關注,但兩者都可以工作,因爲兩者都可以在閉包中捕獲所需的變量,以便您可以在setTimeout回調中引用它們的靜態值。

這裏是一個自我執行的功能將如何工作來解決這個問題:

var end=8; 
for (var i = 1; i < end; i ++) { 
     (function (index) { 
      setTimeout(function() { 
       console.log(index); 
      }, 800); 
     })(i); 
    } 

按比例超時延遲時間設置爲i值,你可以這樣做:

var end=8; 
for (var i = 1; i < end; i ++) { 
    (function (index) { 
     setTimeout(function() { 
      console.log(index); 
     }, index * 800); 
    })(i); 
} 

的自執行函數傳遞的值爲i,並且該函數內包含該值的參數被命名爲index,因此您可以參考index以使用適當的值。

+0

確定它的工作,但如果我想設置超時相關..我怎麼做到這一點?例如,我想把每個數字和延遲數字* 800,如果您只需添加i * 800,則每次循環更改都會延遲1秒。 – alexeyb 2012-04-18 11:25:42

+0

@alexeyb - 您使用名爲'index'的參數。看到我添加到我的答案的第二個例子。 – jfriend00 2012-04-18 16:47:55

相關問題