2011-07-21 116 views
2

我的代碼:的Javascript範圍和調用函數

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

      var x = function() { doStuff(i); }; 
      google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x); 
} 

的doStuff方法只是簡單地提醒我的價值。 mapInfos有兩個條目,所以你希望它提醒0和1,但它會提醒2和2.我可以隱約地理解它爲什麼這樣做(儘管var我應該保持它在本地的循環範圍?)但我怎樣才能使其按預期工作?

+1

Doh-我甚至猜不出這個問題以前有多頻繁。 – jAndy

+0

[你原來的jsfiddle](http://jsfiddle.net/RG3GR/)就是一個很好的例子。 – Pointy

回答

8

編輯 —注意,第一次發佈時,包括原來的問題一個link to a jsfiddle這似乎是什麼的問題,目前正在努力實現一個相關的例子,只是它的工作原理。


jsfiddle中的代碼工作,因爲該代碼中只有一個「我」。第二個循環中使用的「i」(實際調用函數的地方)與第一個循環中使用的「i」相同。因此,你得到了正確的答案,因爲第二個循環通過從零到四個再次的所有值運行「i」。如果你添加了:

i = 100; 
functions[0](); 

你會得到100打印出來。

在JavaScript中引入新範圍的唯一方法是一個函數。一種方法是寫一個單獨的「功能機」的功能:

function makeCallback(param) { 
    return function() { 
    doStuff(param); 
    }; 
} 

然後在您的循環:因爲調用了「makeCallback」功能隔離一個副本

for (var i = 0; i < mapInfos.length; i++) { 
    var x = makeCallback(i); 
    google.maps.event.addListenerOnce(mapInfos[i].map, 'titlesloaded', x); 
} 

這會工作將「i」的值轉換爲返回的閉包中新的唯一「param」實例。

+0

什麼jsfiddle?什麼第二回路? – Quentin

+0

@Quentin問題首次發佈時,有一個jsfiddle鏈接。它與我在問題中添加的評論相關聯。這是一段有趣的代碼:-) – Pointy

+0

對不起,我很快注意到與回答put的人相同的東西,並刪除了JSFiddle,因爲它沒有證實我的問題的其餘部分:) – NibblyPig

1

爲它創建一個新的範圍。

函數創建範圍。

function doStuffFactory(i) { 
    return function() { doStuff(i); }; 
} 

for (var i = 0; i < mapInfos.length; i++) { 
    var x = doStuffFactory(i); 
    google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x); 
} 
+0

eehhr ...'google.maps.event.addListenerOnce(mapInfos [i] .map,'tilesloaded',doStuff(i));'? – jAndy

+1

@jAndy:你現在傳遞調用該​​函數的結果,而不是對它的引用。 –

+0

@Tomalak:夠公平的,記下我自己。 – jAndy

1

將其更改爲

var x = function (param) { doStuff(param); }; 

顯然正在發生的事情是,你是在提醒被改變的變量。通過上述更改,即使我更改了它,它仍會提醒正確的值。

0

的Javascript 有塊範圍,所以你得到x局部於循環。是啊!

雖然它有功能範圍。

0

是的,奇怪的是吧!尖有一個解釋

我不知道爲什麼你的第一個例子中的工作(我沒想到它) 尖有,爲什麼你的第一個例子曾解釋 - 之所以你的第二個沒有,是因爲i的作用域是包含for循環的函數,而不是由for循環定義的作用域。事實上,只有JavaScript中有作用域的東西纔是函數。這意味着當你的函數執行時i2

你需要做的是創建一個範圍,例如:

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

    var x = (function() { 
     return function() { doStuff(i); }; 
    })(i); 
    google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x); 
} 

更多見JavaScript closures in for-loops