Javascript - 事件处理程序中的变量范围

时间:2011-08-09 20:37:11

标签: javascript event-handling scope

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

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'

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

如果我没有很好地表达问题,请原谅我。这是因为对局势非常困惑。我似乎无法通过事件处理程序将我的脑袋包裹在变量范围内.....如果有人可以帮助我澄清,那就太棒了。

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

4 个答案:

答案 0 :(得分:3)

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

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

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


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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

将你的rownum索引设为零。

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

答案 3 :(得分:0)

你的循环变量看起来不正确btw ..不应该用0实例化,否则你只会在地址[1]处绘制标记