Closures in For Loops: In Layman Terms

According to MDN, a closure is the combination of a function and the lexical environment within which that function was declared. For the developer who is new to javascript, this is not exactly straightforward. There are some good explanations already available, but I had a hard time initially understanding how they work in the context of a for loop.

Before we go for a loop, lets go ahead and understand what a basic closure is; if there is such a thing. We’ll be using ES5 terms for simplicity sake.

When inner functions make use of variables in outer functions, we call the inner part a closure. Here is an example where a closure is needed.

function increase() {
var getBig = 0
getBig += 1
return alert(getBig)
}
increase() //1
increase() //1 < —-this should be 2

We could put getBig outside of the function and it will work, but, that would be adding a variable to the global scope(outside of a function) and that’s not good practice . Its possible someone else has used the same variable in their script if you’re using other libraries and this would lead to problems. So what we want to do is enclose getBig in a function and this inner function will be called as many times as needed while the outer function only gets called once.

function increase() {  < — gets called once
var getBig = 0
return function() { < — — gets called each time
getBig += 1 < — — increments each time
alert(getBig)
}
}
var bigOne = increase() < --  a reference to the instance of the   
function
bigOne() //1
bigOne() //2

Before, our variable would be used once and then discarded; it wouldn’t remain in memory. What the inner function does is store the variable or enclose it and future calls will add to it. The inner function remembers the environment in which it was created and has access to the variable in the outer function; that is what’s referred to as closure. This can also be done with an Immediately Invoked Function Expression, but we’re trying to keep it simple here folks.

For Loops

Problem: We have three buttons and when clicking one, we should get it’s index number alerted. This environment has a variable with changing values and only the last assigned value of the variable — 2 — is alerted when clicking any button. It’s like there is a wheel and when we spin it, we’d like it to stop at a certain number or location but there is nothing to stop it so it makes a full spin around which is not what we want.

//HTML Example 
<button>0</button> // click alerts 2 < -- should be 0
<button>1</button> // click alerts 2 < -- should be 1
<button>2</button> // click alerts 2
function registerClicks() {
var btn = document.getElementsByTagName('button')
var len = btn.length
for (var i = 0; i < len; i++) {
btn[i].onclick = function() {
alert(i)
return false
}
}
}

registerClicks()

Solution:We need to create an additional enclosing context that will store the value of i . This is done with a nested function which will ensure that the loop passes the value of i to a placeholder in the inner function when the link is clicked allowing the correct value to be alerted. (Placeholder is just a parameter name and it can be named anything) Now when we spin the wheel, it stops exactly at the number we want it to.

function registerClicks() {
var btn = document.getElementsByTagName('button')
var len = btn.length
for (i = 0; i < len; i++) {
btn[i].onclick = myFunction(i)
}
function myFunction(placeholder) { < — value of i is stored in      
placeholder at time of calling
return function() {
alert(placeholder) < - placeholder not affected by the value of i
changing
return false
}
}
}

registerClicks()

Lexical environment which is also called lexical scope is where every inner level can access its outer levels; basically what a closure is. As The Definitive Guide states about the lexical rule, “functions are executed using the scope chain that was in effect when they were defined.” That means we can have 10 or more functions inside functions and the inner ones will have access to the scope of the outer ones, but not the other way around. A JavaScript master I know — Zeil Lew — says its like one way mirrors. When you are inside…“You can see the outside, but people from the outside cannot see you.”

ES6 introduced the let keyword which is supposed to provide block scope and help developers avoid common mistakes they make. While let does have its place in helping to avoid hoisting, it appears to not be a positive factor when it comes to for loops. I hope this post made sense and I’m sure there is a ton more info I could have included but I wanted to keep it simple and stay true to the ‘layman’ title. Feel free to correct me or leave any comments below.

Moe Himed is a front-end developer and the owner of Critical Web Solutions which offers hosting on cloud servers and dedicated servers.