ref – https://blog.kevinchisholm.com/javascript/javascript-immediate-functions-basics/
In JavaScript, the immediate function pattern is a way of executing a function as soon as it is defined. In this article, I will explain the syntax and explore some of the advantages of using it. This syntax can also be referred to as a closure.
An example of an immediate function:
1 2 3 |
(function () { console.log('test'); })(); |
Basically, it is a function expression which is executed immediately.
The function has to be wrapped in brackets:
1 2 3 |
(function () { console.log('test'); }) |
without the brackets, it is a function declaration
1 2 3 |
function () { console.log('test'); } |
Hence, after we declare the function to be an expression, we execute it immediately by using ()
Alternatively, you can also do it where you have an function declaration, call it by using (), and wrap the whole thing in (…) as an expression.
1 2 3 |
(function () { console.log('test'); }()); |
Why do we do this?
Immediate functions traditionally have two usages:
– defining a function on page load by a conditional
– or for creating a new scope
For example, jQuery plugins commonly use the following syntax:
1 2 3 |
(function ($) { // Plugin code here })(jQuery); |
This is to avoid conflicts with other libraries that use the $ variable. When the jQuery variable is passed to the function as an argument, it is defined as $ in the new scope. And you start using the ‘$’ inside the function to do your code.
In the old scope, the $ is left unchanged.
Let’s Look at an Example
first we have some js that gets all the a tags in the page. We store it as an array into variable anchors.
Then we loop through each ‘a’, and assign a function handler to its click event.
html
1 2 3 4 5 6 7 8 |
<ul> <li><a href="#">one</a></li> <li><a href="#">two</a></li> <li><a href="#">three</a></li> <li><a href="#">four</a></li> <li><a href="#">five</a></li> <li><a href="#">six</a></li> </ul> |
javascript
1 2 3 4 5 6 7 8 9 10 |
<script> var anchors = document.getElementsByTagName('a'); for (var i = 0; i < anchors.length; i++) { console.log(`assigning anchor ${i} to a function`) anchors[i].addEventListener('click', function () { console.log('Anchor number ' + i + ' has been clicked.'); }); } </script> |
The problem is that the var i declared in the for loop is scoped globally. Because in JS, we do not scope to blocks. We only scope to functions. So var i has been hoisted to the top. Thus, when the function is assigned to the ‘click’ handler, it accesses the i as an outer i, like so:
1 2 3 4 5 6 7 8 9 |
var anchors = document.getElementsByTagName('a'); var i; // hoisted for (i = 0; i < anchors.length; i++) { console.log(`assigning anchor ${i} to a function`) anchors[i].addEventListener('click', function () { console.log('Anchor number ' + i + ' has been clicked.'); }); } |
whenever we click on a link, it’ll log the i as 6. Because we’re always accessing the global i.
solution
This can be solved by using an immediate function.
We create a closure by implementing a function around it, with a parameter to pass in the variable i.
This is done by creating a function expression, then executing it right away (IFEE), for each index.
Thus, there will be 6 closures. Each closure holds a different i.
A closure’s respective handlers inside, will access that i.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<script> var anchors = document.getElementsByTagName('a'); var i; for (i = 0; i < anchors.length; i++) { console.log(`assigning anchor ${i} to a function`); // create closure so that we get our own local variable closureIndex (function(closureIndex){ anchors[closureIndex].addEventListener('click', function() { console.log('Anchor number ' + closureIndex + ' has been clicked.'); }); })(i); } </script> |
Now it will work as expected.
Additional Examples
The function is assigned to a variable, and that is it. We have only the function declaration here, but we never call the function. But if you were to add the line “myFunc();” to this code and run it, the output would be: “I am a simple function”.
1 2 3 4 5 |
var myFunc = function(){ console.log('I am a simple function'); } myFunc(); // I am a simple function |
In order to turn this function into an immediate function, we add the open/close parentheses after the closing curly bracket and then wrap the entire function in parentheses. After we do this, we run the code and whatever happens in that function is executed immediately after the function declaration is complete.
1 2 3 |
(function(){ console.log('hello, I am an immediate function'); }()) // hello, I am an immediate function |
We first declare a variable called “myName” before declaring our function. When declaring our immediate function, we take one argument: “thisName”. At the end of the immediate function declaration, the open/close parentheses pass the variable “myName” to our immediate function. So, not only does this set of open/close parentheses execute the function, it also allows you to pass an argument to that function.
1 2 3 4 5 |
var myName = 'bart Simpson'; (function(thisName){ console.log( 'hello, my name is: ' + thisName ); }(myName)) |