我正在尝试将数组传递给函数,然后使用该数组中的信息来初始化Google地图。但是,当我点击地图上的标记时,会产生一个错误:
无法获取属性'popupHtml'的值:object为null或 未定义
创建该函数的原因是,javascript代码可以移动到单独的.js文件,从而与html文件分开。反正这个问题可以纠正吗?这是我的所有代码(我发表评论以标记错误发生的位置......):
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
window.onload = function ()
{
function loadMap(markers)
{
var options =
{
center: new google.maps.LatLng(40.775813, -73.970786),
zoom: 17,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map'), options);
var points = new Array();
for (var i = 0; i < markers.length; i++)
points.push(new google.maps.LatLng(markers[i].lat, markers[i].lon));
var infoWindow = new google.maps.InfoWindow();
for (var i = 0; i < markers.length; i++)
{
var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: markers[i].title });
google.maps.event.addListener(
googleMarker,
'click',
function ()
{
// The following line is where the error is occuring:
infoWindow.setContent(markers[i].popupHtml);
infoWindow.open(map, googleMarker);
});
}
};
loadMap([{
"lat": "40.776512",
"lon": "-73.970293",
"popupHtml": "\u003cdiv\u003eHello world - from marker 1!\u003c/div\u003e",
"title": "Marker 1!"
},
{
"lat": "40.774659",
"lon": "-73.971548",
"popupHtml": "\u003cdiv\u003eHello world - from marker 2!\u003c/div\u003e",
"title": "Marker 2!"
}]);
};
</script>
</head>
<body>
<div id="map" style="width: 680px; height: 400px;"></div>
</body>
</html>
答案 0 :(得分:3)
问题在于,您传入addListener
的功能持久访问i
变量,不其功能的副本创建。因此,函数的所有副本在调用它们时都会看到i
,这可能超过了数组的末尾。同样适用于googleMarker
;他们都会看到循环中的 last 值,而不是当前值。
您使用发电机功能或(如果你可以依靠ECMAScript5,或如果使用一个ES5垫片自bind
是东西垫片可以提供)使用Function#bind
使用bind
:
for (var i = 0; i < markers.length; i++)
{
var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: markers[i].title });
google.maps.event.addListener(
googleMarker,
'click',
(function (index, thisMarker)
{
// The following line is where the error is occuring:
infoWindow.setContent(markers[index].popupHtml);
infoWindow.open(map, thisMarker);
}).bind(undefined, i, googleMarker)
);
}
bind
返回一个函数,该函数在调用时将调用具有给定this
值的原始函数以及您给出的参数。因此,在上文中,我们调用bind
传递i
和googleMarker
的值,它为我们提供了一个函数,当调用它时,它将调用我们的函数原始的那些值作为参数。然后我们使用参数(index
和thisMarker
)而不是i
和googleMarker
。
如果您不能依赖目标浏览器中的ES5功能而又不想使用垫片,则可以使用生成器功能:
for (var i = 0; i < markers.length; i++)
{
var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: markers[i].title });
google.maps.event.addListener(
googleMarker,
'click',
makeHandler(i, googleMarker)
);
}
function makeHandler(index, thisMarker) {
return function ()
{
// The following line is where the error is occuring:
infoWindow.setContent(markers[index].popupHtml);
infoWindow.open(map, thisMarker);
};
}
我们正在调用makeHandler
,传递i
和googleMarker
的值,makeHandler
会返回一个关闭的函数对这些论点(index
和thisMarker
)而不是i
和googleMarker
。由于makeHandler
参数不会改变,我们的函数将看到正确的值。
这一切都与闭包的工作方式有关。关于闭包的更多信息:Closures are not complicated
答案 1 :(得分:0)
您对loadMap函数的定义在window.onload处理程序中,因此在页面加载之前不可用,即使这样,该函数也在不同的范围内。
我认为你的东西有些倒退 - 我将loadMap函数的定义与对loadMap的调用交换,以便调用在onload事件中,而定义则不是。
答案 2 :(得分:0)
正如T.J Crowder指出的那样,i
的值随着循环的进展而变化,即使在闭包期间也是如此。除了他的答案之外,解决这个问题的一个简单方法是在循环范围内创建一个变量。
for (var i = 0; i < markers.length; i++)
{
var marker = markers[i]; // new variable is created for each loop iteration
var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: marker.title });
google.maps.event.addListener(
googleMarker,
'click',
function ()
{
// The following line is where the error is occuring:
infoWindow.setContent(marker.popupHtml);
infoWindow.open(map, googleMarker);
});
}
答案 3 :(得分:0)
你可以使用简单的匿名函数,所以在这里执行一个函数,执行的上下文将保存你的步骤值。
for (var i = 0; i < markers.length; i++)
{
var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: marker.title });
(function(step){google.maps.event.addListener(
googleMarker,
'click',
function ()
{
// The following line is where the error is occuring:
infoWindow.setContent(markers[step].popupHtml);
infoWindow.open(map, googleMarker);
});
)(i);
}