【问题标题】:Why is the Array undefined? [duplicate]为什么数组未定义? [复制]
【发布时间】:2011-06-02 07:39:04
【问题描述】:

当我在地理编码器函数之外提醒我的数组“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);

【问题讨论】:

  • opts.markers 是数组还是对象?
  • 这可能解决不了你的问题,但不要使用for ... in枚举数组:bonsaiden.github.com/JavaScript-Garden/#array.general
  • 你能在 markerArray[i] = marker; 之后插入 console.log(markerArray)在警报之前?并显示结果。您可以在 firebug 或其他浏览器的 javascript 开发工具中监控 console.log 的输出。

标签: javascript function google-maps callback


【解决方案1】:

我怀疑它抱怨的不是 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 不是循环遍历 arrayindexes,而是循环遍历 objectproperty names时间>。 More here. 您要么需要在 for..in 循环中添加一些检查,要么只使用无聊的老式 for 循环。


关于counter:对于习惯于多线程编程的任何人,我简单的“调度时递增,处理时递减”逻辑看起来像是设置了一个竞争条件(如果第一个在之前被回调怎么办?第二个是预定的?)。但这不是浏览器上 JavaScript 中的竞争条件,因为浏览器上的 JavaScript 是单线程的(或者如果您使用 web workers,则类似于协作多线程)。这里没有抢占式多线程。在调度完全部之前,不会调用任何回调。


题外话:虽然var markerArray = new Array(); 工作得很好,但我还是推荐var markerArray = [];。它更短;由于各种原因,实现可以对其进行更多优化(这并不重要);并且不可能有人隐藏了Array 符号。同样,任何时候您只需要一个空白对象,请使用{} 而不是new Object()

【讨论】:

    猜你喜欢
    • 2021-08-01
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多