2014-01-09 14 views
3

我有以下的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的內部匿名函數,我的價值是 '2'。請建議如何在for循環的第一個循環中獲取i = 0,然後在第二個循環中創建1。

+1

查看http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – tewathia

+0

你可以檢查下劃線的每個函數, – jingyinggong

+0

(())會完成,someObj.myMethod( Person [i] [0],function(object){這個函數是一個回調函數,所以我已經設置爲2! – jingyinggong

回答

3

與閉合,這樣的解決方案:

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被共享):)

覆蓋歡呼聲

2

你有泄漏closure。試試這個:

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 has的立即執行的匿名功能,這意味着沒有人可以調用邏輯私人閉合功能(儘管它無疑使得它有點難以閱讀給不習慣JavaScript關閉的人)。

+1

因爲你在9999,所以我會高興的。(好吧,沒錯。 ) –

+0

:)謝謝@lwburk。你是一個紳士和學者。 – Alconja

1

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

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]); 
    }); 
} 
2

它當回調被執行上取決於完全。如果在執行循環時立即執行,則值將如您所期望的那樣。以下產出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元素傳遞給你的回調,而不是他們的數組中的索引。

相關問題