Update:
I've found this question where I did go into more details on closures, comlete with little drawings to clarify how closures, and function scopes are used (and how they can help you).
IIFE's, being function objects, are the only way to create real scopes in JS. They're used all over the place. Have you ever used jQuery, or some other lib? then you've used code that uses IIFE's.
Ever looked into node.js? Then you might have come across something called "the module pattern".
If you've had a go at writing your own constructor, you've probably wondered how you could have some sort of private property onto an object. The answer is IIFE's time and time again.
Also: The DOM api isn't the fastest thing in the world. Having a function containing a hard-coded document.getElementById
call means that, every time the function gets called, the DOM will be traversed. That's not ideal. A quick, and easy way to fix this issue would be this:
var f = (function(domReference)
{
var visible = !!(domReference.style.visibility === 'block')
return function()
{//has access to vars and arguments of outer function
domReference.style.visibility = visible ? 'none' : 'block';
visible = !visible;
}
}(document.getElementById('foobar'));
But perhaps the best, and most common example is timeouts/intervals in loops:
for (var i=0;i<10;i++)
{
setTimeout((function(currentI)
{
return function()
{
console.log(currentI);
console.log(i);
}
}(i)), 1000);
Here, currentI
will log 0, 1, 2... and so on, whereas i
will always log 10
. The reason being the timeout callback doesn't get its own copy of i
's value, but it references the variable i
. That variable can change its value as much as it wants, when the timeout callback is invoked, it'll log whatever value i
was last assigned. Not the value i
was assigned when the callback was defined.
Without going into too much detail, I mentioned private properties for objects. Well, here's an example for you to work out why the IIFE's and function scopes are crucial, and an incredibly powerful feater of JS:
var MyConstructor = (function()
{
return function(foo, bar)
{
var initState = Array.prototype.slice.apply(arguments, [0]);
this.getInit = function()
{
return initState;
};
this.foo = foo;
this.bar = bar;
}
}());
(function(constant)
{
var F = function(args)
{
return MyConstructor.apply(this, args);
},
checkVar = constant || 'default constant value';
F.prototype = MyConstructor.prototype;
MyConstructor.prototype.getConstant = function()
{
if (constant !== checkVar)
{//bad example
return checkVar;
}
return constant;
};
MyConstructor.prototype.regularMethod = function()
{
return this.foo;
};
MyConstructor.prototype.copyFromInitState = function()
{
return new F(this.getInit());
};
}('Immutable value'));
Have fun working this out... :P