当我在地理编码器功能之外提醒我的数组“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);
答案 0 :(得分:7)
我怀疑它不是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`
}
};
}
现在,回调是关于传递到index
函数的buildCallback
参数的闭包,而不是主循环中的i
变量。当我们完成所有回调时我们会发出警报,我们知道这是因为callcounter
(如果您的“竞争条件”雷达正在关闭,请参阅下面的说明)。
所有这一切都是因为闭包的工作方式。它们并不复杂(事实上,我写了一篇关于它们的博客文章称为Closures are not complicated),但有些事情你需要坚定地理解“得到”为什么他们做他们做的事情。
另外:您正在使用for..in
循环遍历opts.markers
,我怀疑它是一个数组。如果是,则该代码存在您需要解决的问题。 for..in
不是用于遍历数组的索引,而是用于循环遍历对象的属性名称 。 More here.您需要在for..in
循环中添加一些检查,或者只使用枯燥的老式for
循环。
重新counter
:对于习惯于多线程编程的任何人来说,我的简单“在调度时递增它,在处理时递减它”逻辑看起来像是设置竞争条件(如果第一个被调用则会怎样)在第二个预定之前回来?)。但它不是浏览器中JavaScript的竞争条件,因为浏览器上的JavaScript是单线程的(或者如果你使用web workers,那就是一种协作的多线程)。这里没有先发制人的多线程。 all 已经安排完毕后,所有回调都不会被调用。
偏离主题:虽然var markerArray = new Array();
工作得很好,但我建议使用var markerArray = [];
。它更短;由于各种原因,实现可以更多地优化它(不是真的很重要);而且某人不可能隐藏Array
符号。同样,只要您想要一个空白对象,请使用{}
代替new Object()
。