Iffe, closures, encapsulations
I have seen a recent flood in articles about Immediately Invoked Function Expressions. Here's the crash course on how they all work:
function outerFunction(){
var outerVar = 5;
function innerFunction(){
return ++outerVar;
}
return innerFunction;
}
var counter = outerFunction();
var counter2 = outerFunction();
console.log( counter() ); //got 6
console.log( counter() ); //got 7
console.log( counter2() ); //got 6
It all comes down to nested / parental scope. What we in JS call "lexical" scope.
This is a more functional example that makes a private contained variable. It does so by returning the innerFunction.
The innerFunction is the only scope that has access to the outerVar, which came from the outerFunction scope. Nothing else can access it outside of the outerFunction.
Whether using anonymous functions or not, arrow functions or not, named functions or not... it doesn't make a difference. The variable in one function scope (inside innerFunction) can see a variable made from an outer function scope if 1 major factor: The function was defined (not run) in the outer function's scope.
So here's the general run down:
- You have a function defined inside the scope of another function.
- A variable is used (but not defined ) in an inner function
- The variable in question was defined in an outer scope.
- The inner function is invoked at a later time (or multiple times later).
In those cases, the inner function will have access to the variables made in the outer scope. Even though technically the outer scope has finished.
That's it! This even works with let and for loops!
for( let i=0; i<3; i++) {
setTimeout( function(){
console.log('value: '+i); //you'll get 0, 1, 2 because each loop is its own scope due to let
}, 3000);
}
If you did that with var, because of the way scope works, you'll get 3, 3, 3
All because of that same aspect of lexical scope. Modules, factories, currying, closures, iffes... they all revolve around that one trick.
So you'll see classic examples like this:
var outerName = 'dude';
(function(){
var innerName = outerName;
setTimeout( function(){
console.log('innerName = '+innerName); //you get dude
}, 2000);
)();
outerName = 'howdy';
(function(){
var innerName = outerName;
setTimeout( function(){
console.log('innerName = '+innerName); //you get howdy
}, 2000);
)();
Notice how the two inner anonymous functions are the same. If you had no outer function, like this:
var outerName = 'dude';
var innerName = outerName;
setTimeout( function(){
console.log('innerName = '+innerName); //you get howdy
}, 2000);
outerName = 'howdy';
var innerName = outerName;
setTimeout( function(){
console.log('innerName = '+innerName); //you get howdy
}, 2000);
(I left the indenting to see the sections that were formally in the code). Notice without the outer function scopes (iffes) to contain their variables, they pulled from the same outerName value at the same rough time.
The importance of scope is reiterated again and it’s amazing. The examples help to solidify the understanding as well. Great article
I was just reading up on closures again. Thanks Dan!