Understanding Javascript self executing functions
A colleague of mine asked yesterday what the point of self-executing functions (SEF) in Javascript was. This is a common question; surely a function, by definition, contains code that you wish to execute at some point later, not right now, no?
Yes, generally. But SEFs do have their uses - if you can get over the theoretical heressy that is a function executing itself.
The most common use of these in my experience is to 'capture' current values when assigning event handlers. Consider the following problem:
1var animal = 'dog';
2$('#someLink').click(function() { alert(animal); });
3animal = 'cat';
When you click the link the alert will say 'cat', not 'dog'. This is because the event callback is evaluated when the event fires - not when it is bound. In other words, our alert will say the current value of animal - not the value as it was when the event was bound.
You could get round this by using a SEF. First a demo, then the science:
1var animal = 'dog';
2var evtCallback = (function(animal) {
3 return function() {
4 alert(animal);
5 };
6})(animal);
7$('#someLink').click(evtCallback);
8animal = 'cat';
The crucial difference here is that our event callback is generated by a SEF. We do this to take advantage of the local scope it provides. When we pass it our animal variable, it takes its own, local copy of it - entirely unconnected with the variable of the same name in the outer scope.
So even though the outer scope animal changes value a few lines later, the copy of this variable in our SEF is fixed to the value it had at the time it was captured: 'dog'.
Obviously if real-world code was as simple as the above, we could just hard-code the word 'dog' in our alert, but you get the idea.
Incidentally, jQuery provides its own shortcut to achieve the above effect, using the bind() method. (bind() is the daddy of event methods; all others, such as click(), effectively get re-routed to this behind the scenes).
It allows you to pass in event data that, like our second example above, will be used in the event callback - protected from anything that happens in the outer scope between now and the time the event fires. Event data is passed as the second argument:
1$('#someLink').bind('click', {animal: 'dog'}, function() {
2 alert(animal);
3});