有人可以澄清我对事件处理程序中变量范围的理解吗?看一下下面的代码:
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”?
过去,我循环遍历对象数组并将事件处理程序绑定(bind)到每个对象。在事件处理程序代码本身中,我会尝试重新引用数组中相应的对象,该对象超出了事件处理程序的范围。因此,在页面加载结束时,所有对象的事件处理程序都引用循环中的最后一个元素。为什么我上面的示例地理编码没有遇到同样的问题?
如果我没有很好地阐明问题,请原谅我。这是因为对情况非常困惑。我似乎无法让我的头脑围绕事件处理程序的变量范围......如果有人可以帮助我澄清,那就太好了。
其他信息/困惑
另一件事...变量 var mark
是在 geocodeCallBack()
的范围内实例化的。当用户在运行时触发 google.maps.event.addListener(marker, 'click', function(){})
时,标记是否会被销毁?在这种情况下,我应该得到某种未定义的错误?
最佳答案
{'address': address[rownum]}
是一个对象文字。因此,它的值是在执行它所属的语句时确定的,并且将来对 address
或 rownum
的更改不会影响对象的 address
成员。
您可能习惯于在闭包(从父作用域引用变量的函数)中看到这个问题。这是一个完全不同的问题,因为函数体通常要在一段时间后才会执行。这样的函数继续引用相同的变量,而不仅仅是相同的值。
但在这种情况下,您根本没有在 for
循环中创建任何函数。
不,marker
变量仍然有效——这是闭包所做的一部分。如果你有 C 背景,这确实会显得很神秘。外部函数已返回;本地人怎么可能继续存在!?
答案是这些变量被匿名函数“封闭”,并且运行时会保留它们的存在,直到不再引用匿名函数为止。
关于Javascript - 事件处理程序中的变量范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7002642/