This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(6个答案)
2年前关闭。
当我在地址解析器功能之外向阵列“ markerArray”发出警报时,它表示未定义。
不知道为什么吗?有没有办法从函数外部的数组中获取值?
现在,回调是传递给
所有这些都是由于闭包的工作方式。它们并不复杂(实际上,我写了一篇有关Closures are not complicated的博客文章),但是您需要牢牢理解一些事情,以“了解”他们为什么要做自己的事情。
另外:您正在使用
题外话:尽管
(6个答案)
2年前关闭。
当我在地址解析器功能之外向阵列“ 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);
最佳答案
我怀疑它不是抱怨的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,则是协作多线程的)。这里没有抢占式多线程。在计划好所有回调之前,将不会调用这些回调。题外话:尽管
var markerArray = new Array();
可以正常工作,但我还是建议使用var markerArray = [];
。它更短;由于种种原因,实现可以对其进行更多优化(这并不重要);而且不可能有人遮盖了Array
符号。同样,任何时候只要您只需要一个空白对象,就使用{}
代替new Object()
。关于javascript - 为什么数组未定义? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6211777/
10-11 06:55