Javascript Functions, Closures, and the IIFE
June 29, 2018, 9:14 am
When writing code in Javascript or any programming language, one of the core concepts that a developer has to wrap their heads around is the function. If variables are values to be referred to at a later time, functions are whole sets of code to be referred to later.
Function
function myFunc() {
// Do something
}
You can also define a function as a value, or as an anonymous function. Normally functions are hoisted to the top of the code and run first, but an anonymous function is created inline with the rest of the code around it.
Anonymous Function
var myFunc = function() {
// Do something
}
There is value in both of these methods. It is important to know your options and explore their relevance. But there are even more options.
Sometimes it can be handy to define a function that defines it's own lexical scope. This allows local variables to be set up statically.
Closure
function foo(){
var id = 5;
var bar = function() {
console.log(id);
}
return bar;
}
var foobar = foo();
foobar();
This series of code has some very interesting implications for scope and how to create functions that have their own values. The id variable only exists inside the foo function, but the foo function returns the bar function as a value, and since the bar function was made inside foo, and after id, it also has access to the id value. Closures allow you to segregate your values and give unique scope to parts of your project. This becomes especially useful when you want to write code for libraries and larger repositories.
Immediately Invoked Function Expression
(function() {
// Do something
})()
Then there is this beast. A function with no name. No real declaration, but put inside of an expression syntax that fires it off immediately. What is the point? Why wouldn't the do something code simply be code, why does it need to be wrapped up like this?
Well, defining a function anonymously allows it to be passed around by value in a much more flippant manner. Most often anonymous functions are used for callback reasons. However, if it tries to access values that were created outside of it's scope it accesses them dynamically at their current value. This can be an unwanted effect, that is most often run into when defining a callback function inside of a loop.
If you make 3 buttons dynamically in a loop, and have them each print out the iterator value on click, all of them will print out the last value, because at the time of clicking, the iterator would have only its final value.
for(let i=0;i<3;i++){
$("body").append($("< button>").click(function() {
console.log(i);
}));
}
This exact situation is when an anonymous function called immediately to provide closure to its scope is most effective. But it gets more complicated. Any method that is expecting a function to be passed into it must receive a function. And a closure that returns a function as a value is a goofy thing to look at.
Anonymous Closure Callback Immediately Invoked Function Expression
var i = 5;
$("button").click(
(function(id) {
return function() {
console.log(id);
}
})(i)
);
i = 10;
Now, that's just weird to look at your first time. It will start to make sense the more you end up using it. The IIFE is being passed a variable in order to give closure to it's current value. The i variable gets passed in at the end of the closure, and then is referred to on the inside as id. This means that no matter what might happen to i in the future, when the click happens, the value of i has been stuck into the static value of 5 in id.
[edit] So um... turns out that loop example doesn't produce the result I said it would which means.... That's not actually a problem when you use the let declaration, instead of the var. But the final example still matters.