Javascript闭包和可变范围

时间:2011-08-10 18:12:48

标签: javascript closures

我正在扩展我的previous question,因为我仍然不完全理解javascript闭包的概念。快速查看以下代码,它将在地图上放置两个标记。 (代码稍微修改了我之前的问题)。

var map = google.maps.somefunctoinstantiatemap();
var address = new Array();
address[0] = '1 Smith Street';
address[1] = '2 Smith Street';
function onpageload()
{
for(var rownum=0; rownum<address.length; rownum++)
{
    geocoder.geocode({
        'address': address[rownum]
    }, function(results, status) {
        geocodeCallBack(results,status,rownum)
    });
}
}

function geocodeCallBack(results, status, argnum)
{
    var marker = new google.maps.Marker({
        map: map,
        position: results[0].geometry.location,
        title: 'arg: '+argnum+' addr:'+results[0].formatted_address
    });

    google.maps.event.addListener(marker, 'click', function(){
        var infowindow = new google.maps.InfoWindow({
            content: marker.title
        });
        infowindow.open(map, marker);
    });
}

好的,多项选择....用户点击两个标记时的结果是什么?

  1. 第一个标记显示'arg:0 addr:1 Smith Street',第二个标记显示'arg:1 addr:2 Smith Street'
  2. 第一个标记显示'arg:0 addr:2 Smith Street',第二个标记显示'arg:1 addr:2 Smith Street'
  3. 第一个标记显示'arg:1 addr:1 Smith Street',第二个标记显示'arg:1 addr:2 Smith Street'
  4. 第一个标记显示'arg:1 addr:2 Smith Street',第二个标记显示'arg:1 addr:2 Smith Street'
  5. 第一个标记显示'arg:undefined addr:undefined'和第二个标记显示'arg:undefined addr:undefined'
  6. 当我运行代码时,答案是3.但我希望答案是4或5.为什么不是4,为什么不是5?

2 个答案:

答案 0 :(得分:4)

你似乎期望闭包关闭某些东西(它确实如此),但是你没有特别使用它在它中关闭的东西(比如循环索引)。 argnum中的geocodeCallBack值来自Google(因为您已将rownum定义为匿名函数的第三个参数,shadowing循环计数器),它是与你的循环计数器无关。

关于该代码的其他几点:

您在顶部的循环循环三次次,而不是两次。您可以从0转到<= results.lengthresults.length2,因此会以rownum012为循环。你的意思是< results.length (你已经修好了。)

这里的匿名功能没有用处:

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

...因为它所做的就是传递它收到的参数。这可能也许应该只是:

geocoder.geocode( {'address': address[rownum]}, geocodeCallBack);

...除非函数的签名是错误的,否则你不应该声明所有这些参数。

修改:根据您的评论,我认为您可能需要这样:

geocoder.geocode( {'address': address[rownum]}, makeCallback(rownum));

function makeCallback(therow) {
    return function(results, status) {
        geocodeCallBack(results, status, therow);
    };
}

...或者在您输入的“真实代码”中,您实际上将该行号用作选择器的一部分:

geocoder.geocode( {'address': address[rownum]}, makeCallback(rownum));

function makeCallback(therow) {
    return function(results, status) {
        geocodeCallBack(results, status, $('#row-' + therow).val());
    };
}

makeCallback函数创建一个函数作为回调。它创建的函数关闭传递给therow的{​​{1}}参数,该参数永远不会更改,因此您为第一个循环创建的回调获得makeCallback therow,并且0therow,表示您在第二个循环中创建的回调。

在理解闭包方面,我写了这篇文章,我认为你可能会觉得有用:Closures are not complicated它介绍了闭包如何工作的机制。标题不是谎言:他们复杂,人们倾向于把自己捆绑在一起,因为他们认为他们很复杂,但他们不是。 / p>

答案 1 :(得分:0)

当您将其声明为函数参数时,

geocode()会覆盖numrow的值。

for(var rownum=0; rownum<=address.length; rownum++)
{
        geocoder.geocode( {'address': address[rownum]}, function(results, status) {geocodeCallBack(results,status,rownum)});
}

尝试这样做,这样geocodeCallBack就会被发送到forloop中声明的rownum

结果应该是第一个标记显示'arg:0 addr:1 Smith Street',第二个标记显示'arg:1 addr:2 Smith Street'