I’m extending my previous question, because I still don’t fully understand the concept of javascript closures. Take a quick look at the following code, which will put two markers on a 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?
- first marker displays ‘arg: 0 addr: 1 Smith Street’ and second marker displays ‘arg: 1 addr: 2 Smith Street’
- first marker displays ‘arg: 0 addr: 2 Smith Street’ and second marker displays ‘arg: 1 addr: 2 Smith Street’
- first marker displays ‘arg: 1 addr: 1 Smith Street’ and second marker displays ‘arg: 1 addr: 2 Smith Street’
- first marker displays ‘arg: 1 addr: 2 Smith Street’ and second marker displays ‘arg: 1 addr: 2 Smith Street’
- first marker displays ‘arg: undefined addr: undefined’ and second marker display ‘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?
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
argnumvalue you get in yourgeocodeCallBackcomes from Google (because you’ve definedrownumas the third argument to your anonymous function, shadowing the loop counter), it’s nothing to do with your loop counter.A few other points about that code:
Your loop at the top is looping three times, not two. You have it going from(You’ve fixed this.)0to<= results.length.results.lengthis2, and so that will loop withrownumvalues0,1, and2. You mean< results.length.There’s no purpose to your anonymous function here:…since all it does is pass on the arguments it receives. That can and probably should just be:
…unless the signature of the function is wrong and you shouldn’t be declaring all of those arguments to it.
Edit: Based on your comments below, I think you may want this:
…or in your “real code” as you put it, where you’re actually using that row number as part of a selector:
The
makeCallbackfunction creates a function to be the callback. The function it creates closes over thetherowargument passed intomakeCallback, which never changes, and so you gettherowbeing0for the callback you create on the first loop, andtherowbeing1for the callback you create on the second loop.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.