簡體   English   中英

如何將變量傳遞給匿名函數

[英]How to pass variable to anonymous function

我想傳遞變量setTimeout函數並用它做一些事情。 當我警告i值時,它會顯示我沒有預料到的數字。 我做錯了什么? 我想要從 1 到 8 的日志值。

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

       }, 800);
   }

解決這個問題的標准方法是使用工廠函數:

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

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

活生生的例子| 來源

在那里,我們在循環中調用makeResponder ,它返回一個函數,該函數關閉傳遞給它的參數( index )而不是i變量。 (這很重要。如果您只是從匿名函數中刪除i參數,您的代碼將部分工作,但所有函數都會看到i在它們運行時的值,而不是最初計划時;在您的示例中,他們都會看到8 。)


更新來自您下面的評論:

...如果我這樣稱呼它會正確嗎? setTimeout(makeResponder(i),i*800); ?

是的,如果您的目標是讓每個調用比上一個調用晚大約 800 毫秒,那將起作用:

活生生的例子| 來源

我試過setTimeout(makeResponder(i),setInterval(i));function setInterval(index) { console.log(index*800); return index*800; } setTimeout(makeResponder(i),setInterval(i));function setInterval(index) { console.log(index*800); return index*800; } 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);
   };
}

活生生的例子| 來源

我認為您現在擁有推進這項工作所需的所有工具。

你的問題是你在一段時間后當你的setTimeout()函數觸發時你引用了變量i到那時, i的值已經改變(它已經到了for循環的末尾。為了讓每個 setTimeout 保持適當的值對於i ,您必須為每個setTimeout()回調分別捕獲該值i

使用工廠函數的前一個答案做得很好,但我發現自執行函數比工廠函數更容易鍵入和遵循,但兩者都可以工作,因為兩者都在閉包中捕獲您想要的變量,因此您可以引用它們的靜態值在 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以使用適當的值。


在 ES6 中使用 let

使用JavaScript的ES6(2015年發布),您可以使用letfor循環,它會創建一個新的,獨立的變量的每個迭代for循環。 這是一種更“現代”的方法來解決這樣的問題:

const end = 8;
for (let i = 1; i < end; i++) {            // use "let" in this line
     setTimeout(function() {
         console.log(i);
     }, 800);
 }

這不起作用的主要原因是因為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);
}

演示

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

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

來源

編輯:在您的示例中, i的有效值可能是8 ,因為該函數僅在循環完成后才被調用。 您需要為每次調用傳遞i的當前值:

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

暫無
暫無

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

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