2011-06-02 67 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