Immediately-Invoked Function Expression (IIFE) and Its Motivation
The use of global variables in Javascript is strongly discouraged for many reasons [1]. Two of the main reasons are the difficulty of controlling access to resources available to the entire application, which can lead to data inconsistency at scale; and the use of global variables causes pollution of the namespace, which can lead to unexpected value replacement due to duplicate variable names. Because of this, Javascript developers are expected to be skilled at managing the scope of their code so as not to use the global scope to store data as much as possible.
One approach to reducing the use of global variables is to use the Immediately-Invoked Function Expression pattern. With this pattern, we can call a function without having to store it, and can ‘hide’ complex code along with the variables inside it that could potentially pollute the global scope of your Javascript application if exposed. To fully understand this pattern, we first need to review functions themselves.
Function Declaration vs Function Expression
In Javascript, when we encounter the keyword function, there are two possibilities: what we have found is a function declaration, or a function expression.
A function declaration is a piece of code that acts like a variable declaration (var, let) for a function. Also like variable declarations, function declarations are affected by hoisting [1:1]. The rule of thumb for identifying a function declaration is that it always starts with the word function. If it does not, then it falls into the second possibility, which is a function expression [1:2]. Function declarations can only be placed at the program level (e.g., global scope) or within another function block.
A function expression is a function that acts/occupies the position of an expression, which is a piece of code that produces a value [1:3]. Besides its placement, what differentiates a function expression from a function declaration is its naming: naming a function expression is optional, unlike a function declaration which must have a name.
// function declaration
function foo() {
// ...
}
// function expression
var foo = function () {
// ...
};
Using a Function Block to Control Code Privacy
Because scoping in Javascript is structured around blocks created by functions, using functions to localize data becomes crucial. When we declare variables or functions inside a function block, they will only be accessible within that function block.
function foo() {
var bar = 13;
function baz() {
console.log(bar);
}
baz();
}
foo(); // 13
console.log(bar); // ReferenceError: bar is not defined
baz(); // ReferenceError: baz is not defined
In this example, bar and baz become “private” variables within the foo function that do not pollute the global scope. Now imagine when we only need the function referenced by foo to be executed once in our application — it would be very costly to have to store it in a global variable. Can we make it execute without having to store its reference in a variable?
Introducing the Immediately-Invoked Function Expression [1:4]
Flashing back to the declaration vs expression section, we learned that function foo() { //.. } as a function declaration only serves to declare the name foo which references a function. Then, as we can observe from the previous code examples, () (called parens, short for parentheses) placed at the end of an already-declared function name will call that function. Based on this logic, can we extract the function and append () to it to execute it immediately without allocating a variable for it?
function() { /* ... */ }(); // Syntax Error: unexpected token '('
We get a syntax error, because the Javascript parser treats function() at the front as a function declaration, and a function declaration must have a name.
The rule of thumb for identifying a function declaration is that it always starts with the word
function.
Now, what will happen if we compromise and give the function a name?
function foo() { /* ... */ }(); // Syntax Error: unexpected token ')'
We get a syntax error again, but for a different reason. This time the error occurs because function foo() { //... } is treated as a single statement [1:5] followed by (). The parens here, rather than acting as a command to execute the function, instead acts as a grouping operator [1:6] that must enclose an expression. Even when we comply and provide an expression inside those parens, the result is not what we expect.
function foo() {
/* .. */
}
1;
/* no error is produced, but nothing happens
/* other than foo being declared
**/
This is because function foo() { //.. } and (1) are treated as two statements that, while valid, are unrelated to each other. Just a function declaration followed by a grouping operator has no meaning.
To make the parser treat the () at the end as a command to execute the function, we need to make the function that precedes it a function expression. The way is simple: just wrap it in parens. This is what Ben Alman named the Immediately-Invoked Function Expression (pronounced “iffy”) — a function expression that is called immediately upon its creation.
(function () {
console.log(3);
})(); // 3
(function () {
console.log(3);
})(); // 3 -- Crockford style
Because the parens enclosing the function declaration only serve to convert the declaration into a function expression, we can omit them when the parser already knows that the statement preceding the second set of parens is an expression.
var foo = (function () {
/* ... */
})();
true &&
(function () {
/* ... */
})();
Nevertheless, Ben Alman recommends continuing to use those parens to improve the readability of our code, as it will make it clearer that the intent of the expression is an IIFE.
Besides parens, there are several other tricks that can be used to “transform” your function declaration into a function expression. These tricks can save one byte, at the cost of the return value and readability [1:7].
!(function () {
/* ... */
})(); // true
~(function () {
/* ... */
})(); // -1
+(function () {
/* ... */
})(); // NaN
-(function () {
/* ... */
})(); // NaN
When using an IIFE, although we can use an anonymous function, Kyle Simpson [1:8] recommends that we still give a name to the function we are calling. This is not only aimed at improving readability, but is also very helpful in the debugging process, especially when our application has grown to a very large scale.
In addition to dramatically reducing global scope pollution, IIFEs also improve the readability of our code in general and enhance the performance of our Javascript programs. Furthermore, IIFEs are very helpful in creating modules — a collection of functions grouped by business logic, that interact with each other and form part of an application.
This article is a summary of Ben Alman_’s discussion of IIFEs on his blog, along with several other sources the author found relevant. Hope it’s helpful._