Advanced Functions: IIFEs, Closures, and the Module Pattern
February 03, 2018
Introduction
In this tutorial, we are going to wrap up the topic of Scopes. We’re pretty sure that you have a solid understanding of how lexical scopes work, and thus you are now prepared to tackle one of the most interesting and sometimes frustrating (not for you; you’ll see) topics: Closures. We could even say that this article has a closure over the first three articles (you’ll get this at the end)! Some developers struggle a lot to understand closures, but only because it’s necessary to master lexical scopes first. We have put a lot of time into mastering the execution context, so it’s very probable that this topic won’t be difficult for you. So, without further ado, let’s start!
IIFEs (Immediately Invoked Function Expressions)
We are going to start with IIFEs (Immediately Invoked Function Expressions). IIFEs do not necessarily use closures, but they are going to be very useful later in this tutorial. An IIFE is, as its name implies, a function that is executed as soon as the interpreter gets to it. This means that we don’t need to call it afterwards. Let’s look at an example:
var global_var = 1;
(function () {
var local_var = 2;
console.log(local_var); //2
global_var = 3;
})();
console.log(global_var); //3
console.log(local_var) //ReferenceError
There’s only one thing that is new to us: as you can see, the function is wrapped in parentheses, and it is called in situ (in the same place that it is defined). We would usually have to first declare the function: function myFunction() {...}
. And then call it: myFunction();
. When using IIFEs, the function is not declared, it is a function expression. As soon as the interpreter gets to it while executing the script, the function gets called, computes something, and then it is gone. It’s no longer a bound object and eventually gets swooped up by the JavaScript Garbage collector.
To reiterate, IIFE, being functions, are able to return values or even interfaces, but the presence of the braces mean that function is bound to life as long as that code is executing. Then it vanishes.
As any other function, is has access to its parent’s lexical scope, that’s why global_var
gets reassigned inside of it. And also, as with any other function, its own lexical scope is gone when the function finishes its computation (that’s why we can’t access local_var
from outside).
Why would we want to do this?
Well, for starters, because an IIFE doesn’t “pollute” our global namespace. When we declare a function in the global scope, the identifier that we use to name it is stored inside of the global namespace. And so, if we try to name another function or a variable with the same name, we will encounter some name collisions. So, when you need to make a computation, but you don’t need that function to stick around for long, then you can call it as an IIFE and get rid of it afterwards.
Another use for IIFEs is in closures, but we’ll talk about that later.
Something that is very important to consider is that, even though an IIFE doesn’t NEED a name, it is a good idea to name it regardless. Naming an IIFE has two advantages:
- It is easier to recognize it in your code.
- It is very useful for debugging.
Besides being able to name an IIFE, as with any other function we can pass arguments to it:
var random_array = ["-", "am", "-", "array"];
(function completeArray(an_array) {
an_array[0] = 'I';
an_array[2] = "an";
joined_array = an_array.join(" ");
joined_array = joined_array + ".";
console.log(joined_array); //I am an array.
})(random_array);
There are two variations of IIFEs. You can choose whichever you prefer. The difference is of style, but they work in the same way.
Variation #1
(function variation1() {
var a = 1;
console.log(a); //1
}());
As you can see, the difference is at the end, in the parentheses that we use to call the function. The first version is (function() {...})();
, and the variation is (function() {...}());
. Pretty simple.
Variation #2
var a_variable = 1;
(function variation2(def) {
def(a_variable);
})(function def(first_variable){
var other_variable = 2;
console.log(first_variable + other_variable); //3
});
In this variation, we pass a function to the IIFE as an argument. The IIFE takes that function, passes an argument to it, and calls it. I know that it looks a lot more complicated than the others. So, why would anyone want to use it? Well, as I said, it is a matter of style. There are some programmers that think that this version is better. Perhaps you won’t use it ever, but it helps to be familiar with it in case you encounter it some day!
Closures
Closures are a fundamental part of how JavaScript works. Enclosing (or encapsulating) data is an essential part to making applications (and it’s functionality) behave predictably, and having a better understanding of what it means can help you build your applications.
A part of JavaScript’s lexical scope, functions act as a filter that prevents values from reaching into other functions, but allowing them to access the values located outside of it. The Closures act like a virtual force field around each function, preventing outside calls from accessing it, while still allowing the protected function context to observe (and assign) available* outside values.
available*, since you can only create objects within the scope you are in, unless using some sort of function or reference to delegate the creation of new objects.
A closure is when a function has access to its lexical scope even when it is called outside of it. Closures are everywhere in JavaScript, we just need to be able to recognize them.
Let’s look at one:
function outerFunction() {
var a = 1;
function innerFunction() {
console.log(a);
}
return innerFunction;
}
var a_variable = outerFunction();
a_variable(); //1
Ok, so, in this example, we are creating an innerFunction
inside of outerFunction
. innerFunction
uses variable a
, which is declared in outerFunction
, to print it to the console. Then, we return the innerFunction
without calling it and assign it to a_variable
. a_variable
contains innerFunction
, and so we can call a_variable
and print variable a
.
How does innerFunction
has access to variable a
even from OUTSIDE of outerFunction
? We would expect that variable a
has already stop existing, as outerFunction
has already finished its computations. Where is that variable stored?
Well, the trick is to think about the way in which lexical scopes work. Remember what lexical scope means? It means that the scope of a function is defined by WHERE in the script that function was defined by the author. The place where that function is written in the code defines its scope, NOT the place where that function is called. And so, in our last example, innerFunction
stores a reference to the scope of outerFunction
and can access it any time.
innerFunction
’s scope chain is something like this:
scope_chain = {
inner_function VariableObject,
outer_function Variable Object,
global Variable Object
}
In each Variable Object (VO), we are storing references to the arguments, variables and functions that were declared at each scope level. That scope chain is a part of innerFunction
’s execution context, and so it exists “inside” innerFunction
.
Let’s look at a classic example:
var some_array = [];
for (var i = 0; i < 3; i++) {
some_array.push(function pushToArray() {
console.log(i);
})
}
some_array[0](); //3
some_array[1](); //3
some_array[2](); //3
In this example, even though we would perhaps expect the console.log()
’s to print 0
, 1
, and 2
, what we get is 3
, 3
, and 3
. This is pretty easy to understand. What we are pushing into the array is a function that contains a reference to the variable i
that was declared in the global scope (remember that variables declared with var
inside of a block statement are created in the scope where the block statement is in). So, each time the function is called, it searches for the value of the global variable i
(3 at the end of the for
loop) and prints it).
We can change this code to make it behave as we would expect:
var some_array = [];
for (var i = 0; i < 3; i++) {
(function createClosure() {
var j = i;
some_array.push(function pushToArray() {
console.log(j);
});
})();
}
some_array[0](); //0
some_array[1](); //1
some_array[2](); //2
What do IIFEs have to do with closures?
Well, we just used an IIFE! That’s right, we use an IIFE to create a new lexical scope at each iteration of the for
loop. What happens when we declare variable j
and assign it the variable i
, is that j
is declared inside of the lexical scope of createClosure()
. And so, when function pushToArray()
is called, it creates a closure over the scope of createClosure()
. Each time createClosure()
is called, it stores in its own Variable Object a variable j
that contains the value of i
at each iteration of the for
loop. And so, pushToArray()
uses that reference to j
to print 0
, 1
, and 2
. Amazing, right?
We could even save some pixels and write it like this:
var some_array = [];
for (let i = 0; i < 3; i++) { //A let variable!
some_array.push(function() {
console.log(i);
});
}
some_array[0](); //0
some_array[1](); //1
some_array[2](); //2
We’ll let you analyze why this works! If you have some doubts, check our last tutorial!
You can see the answer in here:
Ok, so a let variable creates block scopes, right? The way this works is that at each iteration, the i
variable gets reassigned. It is as if at each iteration a new variable was created, and that variable was assigned the value of the last version of i
. As each i
is created along each block scope, then each iteration has its own version of i
. In this way, each time we push function() {console.log(i)}
to some_array, the function that gets stored has a reference to each “version” of i
. Thus, it works as we want it to work!
The Module Pattern
So, why do we want to use closures? Something pretty cool that we can do with closures is to create modules. Modules are a part of a design pattern that is called The Module Pattern. A design pattern is basically a set of rules that allow us to write JavaScript code in a cleaner and better way.
An example of a module could be this:
function Module() {
var an_array = ["Data 1", "Data 2", "Data 3"];
function getData1() {
console.log(an_array[0]);
}
function getData2() {
console.log(an_array[1]);
}
function getData3() {
console.log(an_array[2]);
}
return {
getData1 : getData1,
getData2 : getData2,
getData3 : getData3
}
}
var module = Module();
module.getData1(); //Data 1
module.getData2(); //Data 2
module.getData3(); //Data 3
Ok, so, let’s analyze this.
- First of all, the identifier of the module is written with uppercase letter (
Module
). This is done to state clearly that this function is not just any function, but a module. - Inside of
Module
, we have three functions that take a value stored inside of the variablean_array
and print it to the console. Module
returns the names of the three functions inside of an Object Literal. An Object Literal is similar to a JSON structure. The difference is that an Object Literal doesn’t necessarily has to use strings as keys, and that JSONs don’t allow functions as values.Module
stores that Object Literal in the variablemodule
, and now the inner functions ofModule
can be accessed by using dot notation:module.getData1();
Modules are a way of simulating private and public functions in JavaScript. Private functions are the ones that the module DOESN’T return, and so the user has no access to them. Public functions are the ones that the module DOES return inside the Object Literal, and they can be accessed from outside of the function. This is very similar to the way Object-Oriented Programming works, but we will talk about that in a later tutorial.
More about Modules
Ok, there are other things that we can do with modules. Let’s explore them a little bit further:
var dataForDatabase = ["Mark", "Paul", "Jeremy", "Roger"];
var database = (function CreateDatabase(an_array) {
var _database = an_array;
var publicAPI = {};
function _printData(idx) {
console.log(_database[idx]);
}
function _pushToArray(name) {
_database.push(name);
}
publicAPI.getName = function getName(idx) {
_printData(idx);
};
publicAPI.storeName = function storeName(name) {
_pushToArray(name);
}
return publicAPI;
})(dataForDatabase);
database.getName(1); //Paul
database.getName(3); //Roger
database.storeName("Peter");
database.getName(4); //Peter
Ok, so, a lot of things are happening in here! Let’s break them down:
- We are using an IIFE to store a module named
CreateDatabase
in the variabledatabase
. As we don’t declare the module as a function, this means that we can only have 1 instance of this module. The only instance is in the variabledatabase
and there’s no other way of instantiating another one of this modules. _database
,_printData
, and_pushToArray
are private variables and functions (they cannot be accessed directly from outside of the function). We state clearly that these are private by adding an underscore at the beginning of the identifier (this is just a convention).- We define a variable
publicAPI
and assign an empty Object Literal to it. This type of variable is called a Locally Scoped Object Literal. This makes the code clearer because we can explicitly see when a function is appended to the publicAPI (publicAPI.getName = function() {...};
). - We return the
publicAPI
to store it in the variabledatabase
. - We can also pass arguments to the module AND to the public functions! This gives us a lot of flexibility as you can see.
- When we call the public functions with
database.getName()
anddatabase.storeName()
we are not only accessing the variable_database
and printing its contents to the console, but we are also inserting values into it! This means that the variable_database
that lives in the Variable Object ofCreateDatabase()
can even be modified after the function is called, and the changes are stored to be used later!
As you can see, modules are a very very powerful tool!
The Revealing Module Pattern
One last thing. There is a variation of the Module Pattern that is called the Revealing Module Pattern. This is very similar to what we just learned; the only difference is that it explicitly assigns functions to variables, and then returns the variables inside the object literal:
var arithmetic = (function Arithmetic() {
var add = function addNums(a, b) {
console.log(a + b);
};
var substract = function substractNums(a, b) {
console.log(a - b);
};
var multiply = function multiplyNums(a, b) {
console.log(a * b);
};
var divide = function divideNums(a, b) {
console.log(a / b);
};
var publicAPI = {
add : add,
substract : substract,
multiply : multiply,
divide : divide
};
return publicAPI;
})();
arithmetic.add(3, 5);
arithmetic.substract(6, 4);
arithmetic.multiply(3, 4);
arithmetic.divide(20, 5);
One thing to note is that we are declaring and assigning publicAPI
at the same time, just before returning it. This is another variation that you can use if you like.
Conclusion
IIFEs, Closures, and Modules are some of the most powerful tools in JavaScript. If you learn how to use them well, you can access a myriad of superpowers that will definitely make you a better JavaScript coder. Practice them and master them! And keep on reading, for we are going to explore now a concept that is pretty similar to modules: Object-Oriented Programming. Continue learning to become a JavaScript Grand Master!