2011-06-02 57 views
1

當我在地理編碼器函數外警告我的數組「markerArray」時,它說它未定義。
找不到原因?有沒有辦法從函數外的數組中獲取值?爲什麼數組未定義?

var markerArray = new Array(); 
for(var i in opts.markers) 
{ 
    address = opts.markers[i].address; 
    //alert(opts.markers[i].icon); 
    var geocoder = new google.maps.Geocoder(); 

    geocoder.geocode({ address: address }, function(results, status) { 
     if (status == google.maps.GeocoderStatus.OK && results.length) { 
      if (status != google.maps.GeocoderStatus.ZERO_RESULTS) { 
       map.setCenter(results[0].geometry.location); 
       var marker = new google.maps.Marker({ 
        position: results[0].geometry.location, 
        map: map 
       }); 
      } 
     } 
     markerArray[i] = marker; 

    }); 

} 
alert(markerArray[0].position); 
+0

是'opts.markers'數組還是對象? – jerone 2011-06-02 07:42:11

+0

這可能不會解決您的問題,但不要使用'for ... in'來枚舉數組:http://bonsaiden.github.com/JavaScript-Garden/#array.general – Domenic 2011-06-02 07:44:37

+0

您可以插入控制檯嗎? log(markerArray)在markerArray [i] = marker之後;並在警報之前?並顯示結果。 console.log的輸出,您可以在firebug或其他javascript開發者工具中監視瀏覽器。 – Shamanu4 2011-06-02 07:44:44

回答

7

我懷疑這是不是markerArray,它的抱怨,但markerArray[0]這是不確定的。

您正在使用您在循環中創建的函數調用異步API。這些功能是關閉。他們每個都有一個持久參考i變量,而不是該值的副本,因爲它是定義函數時。所以所有的函數都使用循環中最後的i值,因爲它們都沒有運行,直到循環結束。因此,如果最後一個值i已在循環中爲5,那麼說,然後所有的功能將使用5

此外,在回調有機會運行之前,您會過早地執行alert。您需要在回調之一中進行最後的處理(您可以使用櫃檯來了解它們何時發生的情況)。

您可以同時修改markerArray問題和過早alert這樣的:

var markerArray = new Array(); 
var callcounter = 0; 
for(var i in opts.markers) 
{ 
    address = opts.markers[i].address; 
    //alert(opts.markers[i].icon); 
    var geocoder = new google.maps.Geocoder(); 

    ++callcounter; 
    geocoder.geocode({ address: address }, buildCallback(i)); 

} 

function buildCallback(index) { 
    return function(results, status) { 
     if (status == google.maps.GeocoderStatus.OK && results.length) { 
      if (status != google.maps.GeocoderStatus.ZERO_RESULTS) { 
       map.setCenter(results[0].geometry.location); 
       var marker = new google.maps.Marker({ 
        position: results[0].geometry.location, 
        map: map 
       }); 
      } 
     } 
     markerArray[index] = marker; 
     if (--callcounter === 0) { 
      // This was the last outstanding call 
      alert(markerArray[0]); // Always assuming there was a `0` in `opts.markers` 
     } 
    }; 
} 

現在,回調超過您傳遞到buildCallback功能index參數關閉,而不是i變量在主循環。當我們完成所有回調時,我們會發出警報,我們知道這是因爲callcounter(請參閱下面的註釋,如果您的「競賽狀態」雷達正在關閉)

所有這些都是因爲關閉的方式。他們並不複雜(事實上,我寫了一篇關於他們的博客文章,名爲Closures are not complicated),但有些事情你需要牢固理解,以便「弄清楚」他們爲什麼要做他們所做的事情。

另外:你使用for..in來循環通過opts.markers,我懷疑這是一個數組。如果是,那麼該代碼就有問題需要解決。 for..in不是通過陣列指標循環,它是通過屬性名稱的對象循環。 More here.您可能需要在您的for..in循環中添加一些支票,或者只使用無聊的老式for循環。


的Re counter:要使用多線程編程的人,我的簡單的「調度時增加它,處理時遞減其」邏輯看起來像它建立了一個競爭條件(如果第一個被叫什麼在第二個預定之前回來?)。但這不是瀏覽器JavaScript中的競爭條件,因爲瀏覽器上的JavaScript是單線程的(或者如果您使用web workers,這種協作式多線程)。這裏沒有先發制人的多線程。直到他們有全部被安排,纔會調用任何回調。


題外話:雖然var markerArray = new Array();作品就好了,我建議你var markerArray = [];代替。它更短;由於各種原因,實施可以優化一點(不是真的很重要);並且不可能有人隱藏了Array這個符號。同樣,任何時候只需要一個空白對象,請使用{}而不是new Object()

+0

這個人是正確。 – Domenic 2011-06-02 07:46:33