【问题标题】:Javascript - variable scope in event handlerJavascript - 事件处理程序中的变量范围
【发布时间】:2011-10-23 13:51:22
【问题描述】:

有人可以澄清我对事件处理程序中变量范围的理解吗?看看下面的代码:

var address = new Array();
address[0] = '1 Smith Street';
address[1] = '2 Smith Street';

for(var rownum=0; rownum<=address.length; rownum++)
{
        if(address[rownum])
                geocoder.geocode( {'address': address[rownum]}, geocodeCallBack);
}


function geocodeCallBack(results, status)
{
        var marker = new google.maps.Marker({
            map: map,
            position: results[0].geometry.location,
            title: results[0].formatted_address
        });

        google.maps.event.addListener(marker, 'click', function(){
                var infowindow = new google.maps.InfoWindow({
                content: marker.title
                });
                // how come this event handler knows the marker variable references the marker variable declared about 10 lines above?
                infowindow.open(map, marker);
        });
}

对于大多数人来说,这段代码看起来很简单。它在谷歌地图上绘制了两个标记。当您单击第一个标记时,它会显示地址“1 Smith Street”。当您单击第二个标记时,它会显示地址“2 Smith Street”。

好的,我的问题是:为什么两个标记都不显示“2 Smith Street”

过去,我循环遍历对象数组并将事件处理程序绑定到每个对象。在事件处理程序代码本身中,我会尝试重新引用数组中的相应对象,这超出了事件处理程序的范围。因此,在页面加载结束时,所有对象的事件处理程序都引用了循环中的 LAST 元素。为什么我上面的示例地理编码没有遇到同样的问题?

如果我没有很好地表达问题,请原谅我。是因为对情况很迷茫。我似乎无法用事件处理程序来了解变量范围......如果有人可以帮助我澄清,那就太好了。

其他信息/困惑 另一件事...变量var markergeocodeCallBack() 的范围内被实例化。当用户在运行期间触发google.maps.event.addListener(marker, 'click', function(){}) 时,标记不是销毁 吗?在这种情况下,我应该得到某种未定义的错误?

【问题讨论】:

  • "不显示'2 Smith Street'"?我……我没有看到这里的问题……你是在使用逆向心理学吗?
  • @Joseph - 我期待两个标记都显示 2 Smith Street。但事实并非如此。为什么不呢?

标签: javascript event-handling scope


【解决方案1】:

{'address': address[rownum]} 是一个对象字面量。因此,它的值是在它所属的语句执行的确切时间确定的,将来对addressrownum 的更改不会影响对象的address 成员。

您可能习惯于使用闭包(从父作用域引用变量的函数)看到这个问题。这完全是一个不同的问题,因为函数的主体通常要到一段时间后才会执行。这样的函数继续引用相同的变量,而不仅仅是相同的值。

但在这种情况下,您根本没有在 for 循环中创建任何函数。


不,marker 变量仍然存在——这是闭包的一部分。如果您来自 C 背景,这确实看起来很神秘。外部函数已返回;它的当地人怎么可能继续存在!?

答案是这些变量被匿名函数“关闭”,运行时会保留它们的存在,直到不再引用匿名函数。

【讨论】:

  • 我在问题的末尾添加了其他信息。我在附加信息中陈述的问题是否与您关于闭包的陈述有关?
  • 嘿 cdhowie,很抱歉再次打扰您...我想我没有完全理解您的回答,所以我问了一个相关问题:stackoverflow.com/questions/7015668/…
【解决方案2】:

它没有遇到这个问题,因为您在循环的每次迭代中将address[rownum] 的值传递给geocode 函数。循环完成后您没有引用rownum,这会导致您正在谈论的问题。

【讨论】:

    【解决方案3】:

    从零开始您的 rownum 索引。

    for(var rownum=0; rownum < address.length; rownum++)
    {
            if(address[rownum])
                    geocoder.geocode( {'address': address[rownum]}, geocodeCallBack);
    }
    

    【讨论】:

      【解决方案4】:

      顺便说一句,您的循环变量看起来不正确。不应该用 0 实例化它,否则您只会在地址 [1] 处绘制标记

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-14
        • 2017-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-18
        相关资源
        最近更新 更多