簡體   English   中英

如何在匿名函數調用中獲取外部循環索引?

[英]How to get outer loop index inside anonymous function call?

我有以下javascript代碼:

var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
    someObj.myMethod(Person[i][0], function (object) {
        console.log(i); //this prints 2, I want 0 and 1 as per the loop

        //here I want to access other members of Person[i] array, like Person[i][1], Person[i][2] and Person[i][3]
        //but these console.log() print 'undefined' because i = 2 !!
        console.log(Person[i][1]);
        console.log(Person[i][2]);
        console.log(Person[i][3]);
    });
}

在我的myMethod()里面調用的匿名函數里面,i的值是'2'。 請建議如何在for循環的第一個循環中獲得i = 0,然后在第二個循環中獲得1。

有了一個閉包,這個解決方案:

var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (x = 0; x < Person.length; x++ )
{
    (function(i){   //We add a closure
        someObj.myMethod(Person[i][0], function (object) {
          console.log(i);
          console.log(Person[i][1]);
          console.log(Person[i][2]);
          console.log(Person[i][3]);
      });
    })(x);      //Call the closure function with the value of the counter
}

我將原始計數器更改為x以使其更容易理解(因此您不要將該變量與原始i混淆),但如果它仍然命名為i ,它也會起作用。

這樣,每個循環周期都有自己的變量x不共享 ),所以它不會被for循環覆蓋,導致問題( i被共享):)

干杯

你有一個漏洞關閉 嘗試這個:

var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
    doIt(i);
}

function doIt(i) {
    someObj.myMethod(Person[i][0], function (object) {
        console.log(i); //this prints 2, I want 0 and 1 as per the loop

        //here I want to access other members of Person[i] array, like Person[i][1], Person[i][2] and Person[i][3]
        //but these console.log() print 'undefined' because i = 2 !!
        console.log(Person[i][1]);
        console.log(Person[i][2]);
        console.log(Person[i][3]);
    });
}

基本上,你原來的內部匿名函數正被傳遞到別處以便稍后執行,在哪個階段, i變量已經在for循環中遞增到2 (它們實際上引用了i的一個副本)。 Javascript是函數作用域,所以引入一個新函數和它自己的參數來捕獲i的特定值,你可以將你的匿名函數與for循環中的共享計數器分離。

請注意,您也可以使函數(在我的示例中為doIt )像Edgar一樣立即執行匿名函數,這意味着沒有其他人可以調用邏輯上的私有閉包函數(盡管它可能會讓某些人更難讀用於javascript閉包)。

完全取決於何時執行回調。 如果它們立即執行,則在循環運行時,值將如您所願。 以下輸出01

var someObj = {
    myMethod: function(person, callback) {
        callback();
    }
}

var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
    someObj.myMethod(Person[i][0], function (object) {
        console.log(i); 
    });
}

但是,如果稍后存儲並執行回調,那么(這是理解的關鍵)每個回調存儲已關閉相同的變量i並且在循環完成后該變量的值為2

換句話說, 閉包在變量本身上,而不是在創建閉包時的值 正如其他人所說,使用包含i作為參數的包裝函數可以很容易地解決這個問題。 這會為每個要關閉的回調創建一個變量。

這是一個人為的例子:

var someObj = {

    callbacks: [],

    myMethod: function(person, callback) {
        someObj.callbacks.push(callback);
    }
}

var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
    (function(i) {
        someObj.myMethod(Person[i][0], function (object) {
            console.log(i); 
        });
    })(i);
}

someObj.callbacks[0]();
someObj.callbacks[1]();

在您的情況下,另一個選項是將Person的元素傳遞給您的回調,而不是它們在數組中的索引。

處理閉包問題的另一種方法是創建局部變量並將其傳遞給函數。

var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];

for (var i = 0; i < Person.length; i++ ) {
    var x = i;

    someObj.myMethod(Person[x][0], function (object) {
        console.log(Person[x][1]);
        console.log(Person[x][2]);
        console.log(Person[x][3]);
    });
}

暫無
暫無

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

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