Hacker News new | ask | show | jobs
by Stratoscope 3242 days ago
> 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.