简体   繁体   English

Javascript 闭包和变量 Scope

[英]Javascript Closures and Variable Scope

I'm extending my previous question , because I still don't fully understand the concept of javascript closures.我正在扩展我之前的问题,因为我仍然不完全理解 javascript 闭包的概念。 Take a quick look at the following code, which will put two markers on a map.快速查看以下代码,它将在 map 上放置两个标记。 (The code is slightly modified from my previous question). (代码根据我之前的问题稍作修改)。

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);
    });
}

Ok, multiple choice....what is the result when user clicks on both markers?好的,多项选择......当用户点击两个标记时,结果是什么?

  1. first marker displays 'arg: 0 addr: 1 Smith Street' and second marker displays 'arg: 1 addr: 2 Smith Street'第一个标记显示'arg: 0 addr: 1 Smith Street',第二个标记显示'arg: 1 addr: 2 Smith Street'
  2. first marker displays 'arg: 0 addr: 2 Smith Street' and second marker displays 'arg: 1 addr: 2 Smith Street'第一个标记显示 'arg: 0 addr: 2 Smith Street',第二个标记显示 'arg: 1 addr: 2 Smith Street'
  3. first marker displays 'arg: 1 addr: 1 Smith Street' and second marker displays 'arg: 1 addr: 2 Smith Street'第一个标记显示“arg: 1 addr: 1 Smith Street”,第二个标记显示“arg: 1 addr: 2 Smith Street”
  4. first marker displays 'arg: 1 addr: 2 Smith Street' and second marker displays 'arg: 1 addr: 2 Smith Street'第一个标记显示“arg: 1 addr: 2 Smith Street”,第二个标记显示“arg: 1 addr: 2 Smith Street”
  5. first marker displays 'arg: undefined addr: undefined' and second marker display 'arg: undefined addr: undefined'第一个标记显示 'arg: undefined addr: undefined' 和第二个标记显示 'arg: undefined addr: undefined'

When I run the code, the answer is 3. But I was expecting the answer to be either 4 or 5. Why is it not 4 and why is it not 5?当我运行代码时,答案是 3。但我期待答案是 4 或 5。为什么不是 4,为什么不是 5?

You seem to be expecting the closure to close over something (which it does), but you're not using anything in particular that it closes over in it (like the loop index).您似乎期望关闭关闭某些东西(它确实如此),但您没有使用任何特别关闭它的东西(如循环索引)。 The argnum value you get in your geocodeCallBack comes from Google (because you've defined rownum as the third argument to your anonymous function, shadowing the loop counter), it's nothing to do with your loop counter.您在geocodeCallBack中获得的argnum值来自 Google(因为您已将rownum定义为匿名 function 的第三个参数,隐藏循环计数器),它与您的循环计数器无关。

A few other points about that code:关于该代码的其他几点:

Your loop at the top is looping three times, not two.您在顶部的循环循环了三遍,而不是两次。 You have it going from 0 to <= results.length .你让它从0变为<= results.length results.length is 2 , and so that will loop with rownum values 0 , 1 , and 2 . results.length2 ,因此将使用rownum012循环。 You mean < results.length .你的意思是< results.length (You've fixed this.) (你已经解决了这个问题。)

There's no purpose to your anonymous function here:您的匿名 function 在这里没有任何意义:

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

...since all it does is pass on the arguments it receives. ...因为它所做的只是传递它收到的 arguments。 That can and probably should just be:那可以而且可能应该只是:

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

...unless the signature of the function is wrong and you shouldn't be declaring all of those arguments to it. ...除非 function 的签名是错误的,并且您不应该向它声明所有这些 arguments。

Edit : Based on your comments below, I think you may want this:编辑:根据您在下面的评论,我认为您可能想要这个:

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

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

...or in your "real code" as you put it, where you're actually using that row number as part of a selector: ...或者在您所说的“真实代码”中,您实际使用该行号作为选择器的一部分:

 geocoder.geocode( {'address': address[rownum]}, makeCallback(rownum)); function makeCallback(therow) { return function(results, status) { geocodeCallBack(results, status, $('#row-' + therow).val()); }; }

The makeCallback function creates a function to be the callback. makeCallback function 创建一个 function 作为回调。 The function it creates closes over the therow argument passed into makeCallback , which never changes, and so you get therow being 0 for the callback you create on the first loop, and therow being 1 for the callback you create on the second loop.它创建的 function 关闭了传递给makeCallbacktherow参数,该参数永远不会改变,因此对于您在第一个循环中创建的回调,您会得到therow0 ,而对于您在第二个循环中创建的回调, therow1

In terms of understanding closures, I've written up this post which I think you may find helpful: Closures are not complicated It goes into the mechanics of how closures work in some detail.在理解闭包方面,我写了这篇文章,我认为您可能会觉得有帮助: 闭包并不复杂它详细介绍了闭包如何工作的机制。 And the title is no lie: They're not complicated, people tend to tie themselves up in knots because they think they're complicated, but they're not.标题不是谎言:它们并不复杂,人们倾向于将自己打成结,因为他们认为它们很复杂,但事实并非如此。

geocode() is overriding the value of numrow when you declare it as a function parameter.当您将其声明为 function 参数时,geocode() 会覆盖 numrow 的值。

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

Try this instead, this way geocodeCallBack is sent the rownum that is declared in the forloop试试这个,这样 geocodeCallBack 会发送在 forloop 中声明的 rownum

The result should be first marker displays 'arg: 0 addr: 1 Smith Street' and second marker displays 'arg: 1 addr: 2 Smith Street'结果应该是第一个标记显示 'arg: 0 addr: 1 Smith Street' 而第二个标记显示 'arg: 1 addr: 2 Smith Street'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM