Javascript Closure Tutorial
We will start this Javascript closure tutorial with an fairly common Javascript interview question (in this form or some variant of this form)…
What is the output of the following code…
var myList = [7, 2, 9, 4];
for ( var i = 0; i < myList.length; i++ ) {
setTimeout(function() {
console.log("i=" + i + " : " + myList[i]);
}, 2000);
}
That answer is that this is the output:
"i=4 : undefined"
"i=4 : undefined"
"i=4 : undefined"
"i=4 : undefined"
Not what is expected. But you have to realize that the above is equivalent to as if the “var i” is outside the for loop…
var myList = [7, 2, 9, 4];
var i;
for ( i = 0; i < myList.length; i++ ) {
setTimeout(function() {
console.log("i=" + i + " : " + myList[i]);
}, 2000);
}
By the time loop finishes, i has become 4 (when i is 3 it is still going through the loop). i is 4 already when the console.log’s are executed. Hence you get displayed i=4 and myList[4] is undefined.
The story is different if you change the “var” to “let”, which is one of the solution to fixing the issue:
var myList = [7, 2, 9, 4];
for ( let i = 0; i < myList.length; i++ ) {
setTimeout(function() {
console.log("i=" + i + " : " + myList[i]);
}, 2000);
}
With let, the variable i is bound to exists only inside the for-loop. And the i in the setTimeout is bound to that i. So you get…
"i=0 : 7"
"i=1 : 2"
"i=2 : 9"
"i=3 : 4"
As expected.
Using Closure
A second way to fix the issue to use closure…
var myList = [7, 2, 9, 4];
for ( var i = 0; i < myList.length; i++ ) {
setTimeout(function(i) {
return function() {
console.log("i=" + i + " : " + myList[i]);
}
}(i), 2000);
}
Inside the setTimeout, we immediate call a function that returns a function. The variable i is passed into the outer function. The inner function has access to this variable i even after the outer function has completed. The inner function “remembers” the context it was in when it was created. That is because the inner function creates its own “closure” copy of the environment context for its use later.
Using Javascript Closures to Create Functions
You may be wondering what is the use of closures in real life. One use is in functions that creates other functions. Consider this function called “multiplerCreator”…
function multiplierCreator(amountToMultipleBy) {
return function(thingToMultiple) {
return thingToMultiple * amountToMultipleBy;
}
}
It creates functions. You see that it returns a function. The function that it returns accepts one argument and multiplies it with “amountToMultipleBy”. The “amountToMultipleBy” can be 2. It can be 3. Or it can be anything. It all depends on what was passed to it in the outer multiplerCreator function.
So if 2 was passed into multiplerCreator, then the “amountToMultipleBy” will be 2…
let doubler = multiplierCreator(2);
let answer = doubler(3);
console.log(answer); // 6
answer = doubler(5);
console.log(answer); // 10
In effect, you have a “doubler” function that is produced by multiplerCreator(). You can call this doubler function as shown above.
But if you pass “3” into multiplerCreator(), then it will create a tripler function which multiplies everything by 3…
let tripler = multiplierCreator(3);
answer = tripler(3);
console.log(answer); // 9
answer = tripler(5);
console.log(answer); // 15
Here the point is that the inner function “remembers” its “amountToMultiplyBy” even when after the multiplerCreator() function has completed and disappeared.
Javascript Closure used in Currying
Let say we have a multiper function that multiplies a and b together…
function multipler(a, b) {
return a * b;
}
Say that for our application, this function is too generic. We only just need to multiple by 2 all the time. We only need to multipler function to multiply things by 2. In other words, b is always 2. It would be a hassle to use the multipler function and always have to pass 2 into its second parameter.
Why don’t we create a new function called “doubler” which uses multipler(a, 2). Then we can just pass in the “a” into doubler.
function doubler(a) {
return multipler(a, 2);
}
let answer = doubler(3);
console.log(answer); // 6
answer = doubler(5);
console.log(answer); // 10
Now we don’t have to always pass in the value 2 as the doubler.
Taking this one step further, let’s create a function that produces the doubler function…
function createDoubler(fn) {
return function(a) {
return fn.call(this, a, 2);
}
}
let doubler = createDoubler(multipler);
let answer = doubler(3);
console.log(answer); // 6
The createDoubler function can only create a doubler. If we want a tripler, we would need a createTripler function like this…
function createTripler(fn) {
return function(a) {
return fn.call(this, a, 3);
}
}
Better yet, let’s have a createMultipler function …
function createMultiplier(fn, multiple) {
return function(a) {
return fn.call(this, a, multiple);
}
}
that can create a doubler function …
let doubler = createMultiplier(multipler, 2);
let answer = doubler(3);
console.log(answer); // 6
or a tripler function like this …
let tripler = createMultiplier(multipler, 3);
let answer = doubler(3);
console.log(answer); // 9
Welcome to the world of functional programming.
Using Javascript Closure to simulate a private variable
Here is a createPerson function that has a “private” variable (called _name with underscore to suggest “private”) …
This function returns a “person” object whose _name variable is inaccessible except via the public “getName” and “setName” methods.
It is used like this…
let bob = createPerson("Bob");
console.log(bob.getName()); // Bob
bob.setName("Bobby");
console.log(bob.getName()); // Bobby
Whew… All this closure stuff is making my head spin. Don’t worry if you don’t get it at first. When I first learned it, I had to read about it from 5 different articles and see it explained in multiple ways and times before I “got it”.