Since the first time I read about IIFE, I could not forget this abbreviation. Iffy...
IIFE stands for immediately invoked function expression. It is a JavaScript function that runs as soon as it is defined. It is a design pattern which is also known as a self executing anonymous function.
The syntax looks like this:
// IIFE
(function(){
// do something here
})();
So what do we have here? Let's go into details. The IIFE contains two major parts.
anonymous function
The first part is the anonymous function with lexical scope:
// I am anonymous
function(){
// do something here
};
Hold on a minute what is lexical scope? Check this article for some details on that topic: I would try to explain lexical scope in plain English. Wish me luck.
An anonymous function is a function that was declared without any named identifier to refer to it. It is usually not accessible after its initial creation.
// normal function definition
function hello() {
console.log('A is A');
};
hello(); // output 'A is A'
// anonymous function definition
function(){
// do something
});
A common use for anonymous functions is for example as argument to another function.
// example
setTimeout(function() {
alert('I am John Galt.');
}, 1000);
In the IIFE the anonymous function is enclosed within the grouping operator ()
.
direct interpretation of the function
The second part creates the immediately invoked function expression ()
through which the JavaScript engine will directly interpret the function. The difference to the normal function definition is that with IIFE, declaration and execution are performed at the same time. With the normal function definition you first declare the function and then call it, placing the parentheses after it to indicate that you want to execute it.
why use IIFE?
Ok, so now we know a bit more about the syntax. But what is the benefit of IIFE?
It is about scope. In JavaScript variables declared outside of a function are global variables. Functions declared inside of a function are called local variables.
A global variable can be accessed from anywhere in your code. This comes with some downsides like
- you can (accidentally) access the global state, which leads to impure functions
- you can overwrite other global variables
Imagine you have two JavaScript files and each contains var johnGalt = {};
The variable johnGalt
would be global and therefore shared in all code and executed no matter in which file it was written.
To prevent this the IIFE pattern exists. When you wrap all your global variables into IIFE you take them their globalness. You can treat them as local variables within the IIFE as they are wrapped into a function. The variables within the expression can not be accessed from outside.
(function() {
var johnGalt = 'Who is';
})();
// variable can not be accessed
console.log(johnGalt); // Uncaught ReferenceError: johnGalt is not defined
When you need access to the global variables inside the IIFE you can do something like this:
var galtsGulch = (function() {
var johnGalt = 'Who is';
return johnGalt;
})();
console.log(galtsGulch); // output 'Who is'
If you assign the IIFE to a variable it does not store the function definition but its return value. So everything which is returned by the IIFE function is accessible from outside. This allows you to control what should be globally accessible and what should not.
You can also do some cool stuff and manipulate your global variables inside IIFE. You can do that like this:
var galtsGulch = (function() {
var residents = []; // empty array
return {
// add a resident
add: function(resident) {
residents.push(resident);
},
// get all residents
getAll: function() {
return residents;
}
};
})();
console.log(galtsGulch.getAll()); // []
galtsGulch.add({ name: 'John Galt' });
console.log(galtsGulch.getAll()); // [ Object { name: 'John Galt' } ]
Here the IIFE returns an object with the two keys add
and getAll
. So whenever you access galtsGulch
it represents an object with these two keys. The two keys hold functions that allow you to interact with the residents
variable from outside. add
adds a resident to the array and getAll
gets the complete 'residents' variable.
COOL!
conclusion
With the IIFE pattern it is nearly impossible to accidentally modify or access the shared state. That’s why this pattern is so useful, why it’s commonly used in many applications, and why you should use it, too!
Top comments (2)
Fun fact: Because of how ES6 class definitions work, you can use the same type of syntax as an IIFE for a class definition like so:
This, in turn, is useful for cases where it's much clearer what's going on in an object that you only need a single instance of when it's written out as a class than as an object literal, but you don't want to have to deal with the constructor being in the namespace (local or global). I've seen it used sometimes for constructing default exports for ES6 modules that implement state machines or similar constructs where you need to encapsulate state as part of the module itself.
This works because an ES6 class declaration is an expression that evaluates to the constructor function for the class itself, which you can then immediately invoke (but don't forget the
new
, otherwise you'll get weird behavior).Hi Austin,
cool! Thanks for sharing this additional input here!