Resolve scoping issues in jQuery with anonymous functions
Posted on May 21, 2011
I had a bit of a head-scratching moment recently when I was using jQuery to bind event handlers to elements in a loop. Usually I would just use jQuery’s .each() method but in this specific case that wasn’t an option. Consider the following (simplified) code:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <ul> <li id="item-1">Item 1</li> <li id="item-2">Item 2</li> <li id="item-3">Item 3</li> </ul> <script type="text/javascript"> for ( var i = 1; i <= 3; i ++ ) { $('#item-' + i).click(function() { alert('You clicked item ' + i); }); } </script> |
Against my intuition, clicking any of the three li elements would return return “You clicked item 4”. I then realized that i was being read after the for-loop had finished. To solve this, wrap the function in another anonymous function passing i as an argument:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <ul> <li id="item-1">Item 1</li> <li id="item-2">Item 2</li> <li id="item-3">Item 3</li> </ul> <script type="text/javascript"> for ( var i = 1; i <= 3; i ++ ) { (function(i) { $('#item-' + i).click(function() { alert('You clicked item ' + i); }); }(i)); } </script> |
This way the second i lives in the same scope as the alert() function which will now return the correct value.
