异步调用的可变引用问题

时间:2012-11-22 21:34:10

标签: javascript

我一直在玩JavaScript,而且我不太明白。我在这里有这段代码:

$.getJSON('data.json', function(obj) {

    for( var p in obj.List )
    {               
        datas['id'] = obj.List[p].ListingId;
        datas['area'] = area;

        //console.log(datas);

        var geocoder = new google.maps.Geocoder();              
        geocoder.geocode( { 'address': datas['area'] }, function(results,status)
        {

            if(status == google.maps.GeocoderStatus.OK)
            {
                var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);

                datas['latlng'] = latlng;

                //console.log(datas);                       

            }                               
        });
     }      
});

好的,现在假设for循环运行3次。如果我们取消注释第一个“console.log(datas)”行并运行页面,在控制台中我们会看到3个“数据”对象,它们有自己的“id”和“area”。如果我首先评论“console.log(datas)”并在地理编码回调中取消注释第二个“console.log(datas)”,那么当我运行代码时,所有3个“数据”对象在“ id“,”area“和”latlng“。虽然我预计3个“数据”对象与他们自己的latlngs会有所不同。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我认为这是一个范围问题。到最后console.log次运行时,p变量已经引用了最后一个obj。您需要在新范围内捕获p

for( var p in obj.List ) { 

  (function(p) {

    datas['id'] = obj.List[p].ListingId;
    datas['area'] = area;

    geocoder.geocode( { 'address': datas['area'] }, function(results,status) {
      ...
    });

  }(p));

}

答案 1 :(得分:1)

您传递给geocoder.geocode函数的函数何时运行?如果它没有立即运行,则for循环将在运行地理编码功能之前运行三次。这意味着datas['id']datas['area']将被设置为循环的最后一次迭代...在这种情况下,您需要捕获地理编码函数的闭包内的数据数组。

在这种情况下,您需要以下内容:

$.getJSON('data.json', function(obj) {

    for( var p in obj.List )
    {               
        datas['id'] = obj.List[p].ListingId;
        datas['area'] = area;

        //console.log(datas);

        var geocoder = new google.maps.Geocoder();              
        geocoder.geocode( { 'address': datas['area'] }, function(datas){ return function(results,status)
        {

            if(status == google.maps.GeocoderStatus.OK)
            {
                var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);

                datas['latlng'] = latlng;

                //console.log(datas);                       

            }                               
        }}(datas));
     }      
});

这可以防止由for循环更新匿名函数使用的数据变量。

答案 2 :(得分:0)

我认为必须将数据声明为全局数组?有吗?