Immediately Invoked Function Expressions ~ IIFE
An imediately invoked function expression (IFFE), pronounced âiffyâ, is a JavaScript design pattern often used to minimize naming conflict and create private variables.
The conventional format for an IFFE is to enclose the whole function within the grouping operator (a set of parentheses) and to leave it unnamed (i.e., anonymous). The additional set of parentheses at the end is what immediately invokes it:
Before we get into IFFEs at a more detailed level, letâs review the differences between function declarations and function expressions.
Function Declaration vs Function Expression
A âfunction declarationâ (synonymous with âfunction statementâ) requires the keyword function
, a name (i.e., what follows function
), and a function body (whatâs between the curly braces). When a JavaScript file (or HTML document containing JavaScript) is loaded, function declarations are hoisted (moved) to the top of the code before any code is executed.
An âexpressionâ is any valid unit of code that resolves to a value. The main difference between function declarations and function expressions is that when using function expressions, the name can be omitted, creating an anonymous function. Further, function expressions are not hoisted; the they are not loaded until the JavaScript interpreter reaches them in the script. If you try to call a function before that point, youâll get an error.
The reason you can store an IIFE in a variable (a feature of function expressions in most contexts, one exception being callbacks [when theyâre passed as a parameter to another function]) is that function expressions return a value (as all expressions do).
IFFEs Help to Minimize Naming Collisions
Itâs widely considered good practice to minimize pollution of the global namespace (having many different named variables and/or functions in the global scope) to reduce the chances of naming collisions.
Defining variables inside functions or between curly braces makes them inaccessible to the global namespace. (In case you need a refresher, var
[which itâs better not to use anymore] is function or global scoped, while let
and const
can be either global [not between curly braces] or block scoped [between curly braces].) Creating private/local scope (making variables, etc., inaccessible in global/public scope) is not a special feature of an IIFE; you could just define the variables inside a regular function as the example below demonstrates (or simply between a set of curly braces if youâre using let
or const
).
This being said, with an IIFE, you can use an anonymous function and eliminate the chances of it being returned more than once.
You can store the IFFE in a variable, since function expressions evaluate to a (function) value â whereas function declarations, being statements, donât evaluate to anything.
Does an IIFE Need Enclosing Parentheses?
If you assign the IIFE to a variable, the enclosing parentheses can be omitted:
If you donât assign the IIFE to a variable, surrounding it with parentheses is necessary for it to still work because without them, as soon as the JavaScript interpreter arrives at the function
keyword, it will assume it has encountered a function declaration (resulting in an error message that a name is needed) .
But, of course, donât add a name â that would be fulfilling the requirements for the function to be considered a function declaration, but an IIFE requires the function to be an expression (hence the word âexpressionâ!).
If for some reason you donât want to use enclosing parentheses, you can circumvent the need to use them by preceding the function with an exclamation point, which forces the JavaScript interpreter to treat whatever follows as an expression:
There are other ways to force the JavaScript engine to interpret a function as a function expression:
Alternative Syntax for IFFEs
There are two ways to format an IFFE (assuming youâre using enclosing parentheses). You can use either style; itâs a matter of personal preference.
Style 1:
Style 2:
Do IIFEs Have to Be Anonymous?
IFFEs used to be called âself-invoking anonymous functions,â but the name was changed to what theyâre now called in part because the word âanonymousâ was deceptive. For instance, this is perfectly acceptable:
IFFEs and Closures
You can also utilize closures inside IFFEs.
Hereâs an example of a closure in a regular (non-IFFE) function. (The inner function, as well as the count
variable it references, comprise the closure.)
Below is a closure in an IFFE.
Both of these examples of closures have the benefit of preserving the value of count
in subsequent function calls, whereas if a closure were not used, count
would be reset to zero following each function invocation. Further, in both cases the count
variable (as any let
variable in a block) is private â that is, not globally accessible.
While the closure in the first (non-IFFE function) example can be called to reset the iterator whenever desired, the closure in the IFFE cannot be reset since the whole function is only run once (subsequent calls are to the function within the IFFE).
An advantage of using the IFFE version of the closure over the non-IFFE version is that you donât have to name it (you just have to assign it to a variable in order to call it again) â or if you do name it, it wonât be visible in the global scope â so thereâs one fewer item polluting the global namespace.
Hereâs another example of an IIFE containing a closure:
The variable add
stores the result of executing the outer function (the IFFE). Itâs only executed that one first time, in which it sets count
to zero and returns the function expression within it. Itâs important to note the inner function is not run when the IFFE is created; it must be called before the incrementation of count executes and its result is returned.
So, once the IFFE is assigned to add
, each time add()
is called, the inner function is executed. This increments and returns the updated count
variable. The number that appears in the console after running this code is the updated value of count
returned by the inner function.
Last updated
Was this helpful?