| > Closures are a great way to maintain private variables in JavaScript but also seem to be a source of great misunderstanding. Very true on both counts, but unfortunately the article perpetuates some of this misunderstanding. > Where it gets interesting is when you return a function from an outer function... Abbreviated example from the article: var outer = function () {
var a = 1;
return function inner() {
return a;
};
};
...and that's the only example. No mention of where closures are actually most useful, and not a peep that you don't need a function that returns a function to get one. Any function call can get you a closure.I deal with this frequently on Stack Overflow. Someone asks a question where a closure is a great solution, and then someone answers with a complicated example involving a function that returns a function. It seems to come up a lot in Google Maps API code: var places = [
{ name:"Test", lat:10, lng:10 },
...
];
function initMap()
var map = new google.maps.Map(...);
for( var i = 0; i < places.length; ++i ) {
var marker = new google.maps.Marker(...);
// This is the complicated part:
marker.addListener( 'click', (function( marker ) {
return function() {
// This works because of the closure:
infowindow.open( map, marker );
}
})( marker ) );
}
}
It doesn't have to be done that way! You'll get a closure that works just as well if you simply call a function in the loop: function initMap()
var map = new google.maps.Map(...);
for( var i = 0; i < places.length; ++i ) {
addMarker( places[i] );
}
function addMarker( place ) {
var marker = new google.maps.Marker(...);
marker.addListener( 'click', function() {
// We have a closure here too:
infowindow.open( map, marker );
});
}
}
There are other ways to do this in modern JavaScript (such as using let inside the loop). I'm using old-school JavaScript here just to show that it could be done this simply even in the oldest browsers.Of course, the same thing can be done with forEach(): function initMap()
var map = new google.maps.Map(...);
places.forEach( addMarker );
function addMarker( place ) {
var marker = new google.maps.Marker(...);
marker.addListener( 'click', function() {
// We have a closure here too:
infowindow.open( map, marker );
});
}
}
Or with the forEach callback inline: function initMap()
var map = new google.maps.Map(...);
places.forEach( function( place ) {
var marker = new google.maps.Marker(...);
marker.addListener( 'click', function() {
// We have a closure here too:
infowindow.open( map, marker );
});
});
}
The point in each of these cases is that you don't need a function that returns a function to get a closure, but people who answer SO questions perpetuate this myth day after day. |