If we take the above definition into account then what about the below scenario? We are running a function as soon as it is defined. There is no statement between the definition and the call. Does that make an IIFE?
I in IIFE stands for
immediately but it does not signifies that immediately running a function makes the function an IIFE. I am also intrigued by the use case everybody uses in their tutorials - If you want to write a function and call it immediately. Did you ever come across such a scenario? Functions are there for a purpose. They give you the power of reusability. If you write a function that means you want to re-use it.
In this article I shall try to explain the practical use case of IIFEs and where they fit in our day to day development. I have read almost all the articles which appear on the first page of google on searching for
IIFE. I have watched many videos on youtube explaining IIFE. And it turns out that each of them fails to explain the idea behind IIFE and its use case.
- How closures work
- Function declaration vs Function expression
- Function scope and nesting scopes
- Operator precedence and grouping - Very important!
- Idea of how code is parsed by the compiler
Almost everyone focuses on the scope created by the IIFE. Though in reality its about the parent scope. We shall learn every bit in a minute. Web is filled with contrived examples like below which work but miss the point of having an IIFE.
A common way to solve the above problem is to add an IIFE to the code.
This works but its not because of IIFE. You can achieve it using regular functions also. All you need to do is to remove the closure of
i so that the setTimeout function gets a different value each time.
Similarly there are number of articles which talk about other things like advantage of having a private scope with IIFE. Yes, that is true but its just that all those advantages are just because every IIFE is a function.
Apparently, there is only a single post from the hundreds which actually explains IIFE in its entirety with purpose and usefulness. And surprisingly its from 2010 by Bel Alman. Do check it out. It even gives an intro why we call this concept as IIFE.
Libraries like Jquery need to instantiate only once and return a variable like
jquery to the global scope, they need a mechanism for this. And before ES6 it was only possible with IIFEs. We will go in-depth in a minute.
With ES6 modules you no longer need IIFEs for the most part. Thus they were mostly reserved for library creators or framework architects. As an application developer you would not use IIFE in your day to day work.
The Scope dilemma
One aspect that I think everybody gets wrong about IIFE is the clause -
prevents global scope pollution. Though its true but it does not gives you the differentiating factor. There are several caveats attached to it.
Lets understand the whole scope pollution thing in detail. Every where its mentioned that
any variable declared inside an IIFE is local to it and does not pollute the global scope.
The statement is factually correct BUT remember that every IIFE is just another function. So as a result anything declared inside an IIFE will be available only inside the function body and will not be visible outside thereby preventing the outside scope to get modified. There is nothing special here. Every function has the same characteristic.
Thats the whole purpose of having functions in a language.
In fact you can accidentally create global variables in IIFE just how you would do in a regular function. Thereby modifying(you can say polluting) the parent scope.
You can also modify the parent scope with arguments just as what you can do with normal functions.
Remember IIFEs are just functions. So everything that is applicable to functions is valid for IIFEs. Then what's the fuss?
Its all in the name
- Function declaration
- Function expression
In the declaration you are creating a function named loadData which will be available in the parent scope. The parent scope could be global or it could be another function scope.
In the expression, its slightly different, but still you are creating a variable named
loadData in the parent scope. The only difference is that the value of the variable will be a function and will only be assigned to the variable after the assignment statement executes.
As you can see in both of them, you are eventually creating an identifier
loadData in the parent scope. In essence whatever you do, you would have to ultimately modify(you can say pollute) the parent scope to run your code.
This is where IIFE comes into picture. IIFE gives you the power to run code without modifying the parent scope. And this is the only thing that makes it different from regular functions. Everything else is just a side-effect of being a function.
Any other characteristic is just an utility of IIFE. For example its said that if you want to run some code exactly once, you should use IIFE. No. You don't need to use IIFE. You can always write your code within a function(which makes it modular) and just call it once in your application.
Unless you are creating a library or creating a module, 99% of the time you would not need an IIFE. You could, but you should not!
Practical use case of IIFE
Jquery uses IIFE to instantiate itself. Remember that jquery does modify the parent scope but it does so without adding any function identifier. Depending on whether you are using the
noConflict flag, jquery will add
jquery to the window object.
Below is the trimmed down version of jquery.
You can see that jquery covers all its code inside an IIFE. In the parameters it passes the window object and the factory function. The factory function itself is an anonymous function expression but within jquery code it is referred to as variable
After removing the comments it becomes easier to identify the IIFE.
Further if I rename the variables, you can easily make out the structure of the function.
y are values passed in from the parent scope as arguments to the IIFE.
The IIFE function does not change the parent scope. So you do not have to do something like this in your script.
Since IIFE accepts arguments just like a regular function and then operates on those arguments thereafter. In this case the first parameter is the global object and second parameter is the factory function. It doesn't matter if parent scope is
global or anything else. Within the function its always referred to as
Do remember that since
a is just a reference to the outer scope value, you can still modify it. And that's what jquery does. It attaches itself to the
gloabl object. Now you must have understood that using an IIFE just makes it possible to run the whole code without creating a function identifier in the scope.
Almost every library would use IIFE to setup initially which is required to be run only once when you load the appliaction.
So many ways to create
Now you know that you can create an IIFE by just surrounding any function with parenthesis and another set of parenthesis to call that function.
But this is not the only way to create an IIFE. You can use below techniques as well
And that's why mostly IIFEs are created using parenthesis. This method also has two varieties.
The difference is whether you want to call the expression result or the function expression individually. This is better understood when there are more expressions in a group.
In the above example the group has two expressions. One is a function and the second is a string. Yes an individual string is also a valid expression. More on that in a different article. Grouping operator works from left to right and will return the last expression result. So in this case it returns a string
str. That expression result is then called because of the outer parenthesis. Since
str is not callable, this goes into error.
If you move the parenthesis inside the group, you segregate the expression call. Your first expression in the group becomes an IIFE and second expression is just a string. On completion of all the expressions in the group, the result is the value of the last expression which here is a string. Now we are not doing anything with this result and therefore we do not get any error.
The former is the most used method but Crockford recommends the latter one. Maybe its because you can mess up the IIFE the moment you add another expression to the group.
Named IIFE vs Anonymous IIFE
Another confusing thing about IIFEs is the name of the function. As mentioned earlier that the whole idea behind using an IIFE is that it saves you from declaring a name in the parent scope. Then if we give a name to the function does it stop being an iife and gets converted into a normal function?
The answer is No. The name that we have given to the function is only for its own scope. This name does not go out to parent scope. You would ask then is there any benefit of giving a name like this? Yes, the name can be then used within the function if required.
Below is another good read to understand how functions work