It is an anonymous function that get invoked as soon as it is defined.
It is all about this block of code
(function(){
//body
}());
It's important to understand the difference between function declaration and expression to understand how IIFE works
-
Function Declaration: A function declaration defines a named function variable without requiring variable assignment. example
function printName() { console.log("Amr Labib"); }
-
Function Expression: A function expression, defines a function using a variable assignment expression. example
var printName = function(){console.log("Amr Labib");}
-
In javascript, trying to immediately invoke function declaration is not possible it will result in an error.
-
To be able to immediately invoke a function declaration using the trailing parentheses
()
you need to tell the parser to expect an expression.
In this example we will show the difference between immediately invoking function declaration and expression .
//function declaration
function printName(){
console.log("Amr Labib");
}() //SyntaxError: Unexpected token ) because parser considers parentheses () a completely different expression not related to the function and it expected to have an actual expression inside the parentheses like (1+2) but found nothing.
//function expression
var printName = function(){
console.log("Amr Labib");
}() // Amr Labib --> because parser found function expression before (), and the parentheses correctly invoked the function
We have multiple ways to tell the parser to expect an expression instead of declaration when it encouter function keyword, and this will make it possible to immediately invoke the function.
-
Wrap the function declaration inside parentheses (). "this is the most used way"
-
Prefix function with unary operation, or add the function declaration in logical operation.
(function(){
console.log("this function is immediately invoked");
}()); // this function is immediately invoked
!function(){
console.log("this function is immediately invoked");
}(); // this function is immediately invoked
true && function(){
console.log("this function is immediately invoked");
}(); // this function is immediately invoked
It is better to make code more readable and use the most common used way.
One of the most confusing things about IIFE is the way it accept its parameters, because we pass them at the bottom of the function while invoking it.
One of the common mistakes while passing parameters is to mix function definition parameters and the actual passed parameter during invoking the function.
// Wrong way
var x = 1;
var y = 2;
(function(x,y){
console.log(x + y);
}());
//NaN --> because x and y are both undefined
// The right way
var x = 1;
var y = 2;
(function(x,y){ //x and y here are just the function definition parameters
console.log(x + y);
}(x,y)); //Here we pass actual values of x and y
// 3 --> because we passed x and y at the bottom of the function while invoking it.
// Better less confusing way
var x = 1;
var y = 2;
(function(num1,num2){ //changed funtion definition parameters names to make it clear that they are different from the actual passed values while invoking it at the bottom
console.log(num1 + num2);
}(x,y)); //Here we pass actual values of x and y
// 3 --> because we passed x and y at the bottom of the function while invoking it.
-
One of the common uses of IIFE is the module pattern (namespace) implemented as a singleton.
-
Commonly used with closures, to capture specific values in execution context.
-
Generally any situation when you need to invoke an anonymous function once, without adding any variables to polute the global scope with one more variable!
Module pattern
var Module = (function () {
//private variable and method can't be accessed using Module.increment
var num = 1;
var logNum = function () {
console.log(num);
};
return {
//public methods, we say they are public because we can access them using Module.increment or Module.decrement
increment: function () {
num++;
logNum();
},
decrement: function () {
num--;
logNum();
}
};
})();
Module.increment(); //2
Module.increment(); //3
Module.decrement(); //2
Module.logNum(); //TypeError Module.logNum is not a function --> because logNum is private method inside the module
Save state with IIFE and closure, this is a copy from Example 4.3 used in closures section but using IIFE instead of named function.
Capture the value of i
inside each loop.
var printValuesArr = [];
for(var i = 0 ; i < 10 ; i++)
{
printValuesArr.push((function(capturedI){
return function(){
console.log(capturedI);
};
})(i)); //this is how we captured the i value by passing it to the IIFE in each iteration
}
printValuesArr[0](); //0
printValuesArr[5](); //5
printValuesArr[9](); //9