How to use functions and closures inside a loop in JavaScript

How to use functions and closures inside a loop in JavaScript

In this post find the quick and simple solution for how to use functions and closures inside a loop in JavaScript - Quick Fix Series!

Will Mayger

A post by Will Mayger
August 05, 2021

In this quick post we will be covering how to use functions and closures inside a loop in JavaScript so you can solve this issue quickly and without having to look any further!

As with all my Quick Fix Series of posts, you will first find the problem described and then the solution just below.

Let’s get stuck in!

The Problem - JavaScript functions and closures inside for loops

The problem with using closures in JavaScript for loops comes primarily from using the var statement to declare a variable.

var statements in non-strict mode are not block scoped which means that their values will leak out into the parent scope as well.

For example consider the following:

var n = 1

{
  var n = 10
}

console.log(n) // 10;

Because the var statement used to declare the variable n is not block scoped that means that the outer variable that has also been declared as n then gets re-defined to be 10 even though the value of 10 is being declared in the child block.

So when it comes to using a for loop this should help explain why using a closure inside of a for loop using var is problematic.

Here is another example using a for loop this time:

for (var i = 0; i < 3; i += 1) {
  console.log(i) // 0, 1, 2
}
console.log(i) // 3

You might have expected that the last console.log shouldn’t have logged anything because the variable i shouldn’t be accessible outside of the scope of the for loop block, but because a var has been used, it is.

Now let’s take a look at the problem when using functions or closures within a for loop now.

const exampleFunctions = []

for (var i = 0; i < 3; i++) {
  exampleFunctions.push(() => {
    console.log(i)
  })
}

for (var j = 0; j < 3; j++) {
  exampleFunctions[j]() // 3, 3, 3
}

Now in the above example with our function and the for loop, you can see that after we loop over every function to log what has been stored, it always logs the number 3 and not the numbers 0, 1, 2.

We can understand why this happens when we remember how var statements are not blocked scoped.

What this means here is that when we create a function in the first loop, we are not creating the function with the numbers 0, 1, 2 but instead we are creating the function with the variable i which is just a reference to whatever it was last defined as.

So in the second loop, when we log the variable for each function, it then looks for the variable i, which as we have seen in the above is now of value 3 so it will always log 3.

To be more verbose about this here is how this would look in the code if we were not using a for loop:

const exampleFunctions = []
var i = 0
exampleFunctions.push(() => {
  console.log(i)
})
exampleFunctions[0]() // 0

var i = 1
exampleFunctions.push(() => {
  console.log(i)
})
exampleFunctions[0]() // 1
exampleFunctions[1]() // 1

var i = 2
exampleFunctions.push(() => {
  console.log(i)
})
exampleFunctions[0]() // 2
exampleFunctions[1]() // 2
exampleFunctions[2]() // 2

var i = 3

exampleFunctions[0]() // 3
exampleFunctions[1]() // 3
exampleFunctions[2]() // 3

As you can see the variable i is always referencing the latest version of it which is exactly what you would expect to happen, the only reason why this gets a little confusing is because we expect the function to hold the value of the variable at the time we create the function.

Let’s take a look at some of the solutions to how we can solve this issue.

How to use functions and closures inside a loop in JavaScript

The easiest way to solve this problem is to make use of the let statement instead of the var statement when declaring the variable for a for loop.

The reason why this works is because a let statement, unlike a var statement, is block scoped. This means that if you define a variable using let in a block it will stay in that block and it won’t pollute the parent scope.

Because of this the only reference to the variables in the for loop is at the time of creation of the function.

Here is an example of using let to use functions and closures inside a loop in JavaScript:

const exampleFunctions = []

for (let i = 0; i < 3; i++) {
  exampleFunctions.push(() => {
    console.log(i)
  })
}

for (let j = 0; j < 3; j++) {
  exampleFunctions[j]() // 0, 1, 2
}

Another solution here is to make use of a closure to be able to protect the value at that point in time so we can reference it for each loop of the for loop.

To do this we just need to create a function using a closure.

Here is an example of how to use a closures inside a loop in JavaScript to solve this issue:

const exampleFunctions = []

const encloseValue = value => () => {
  console.log(value)
}

for (var i = 0; i < 3; i++) {
  exampleFunctions.push(encloseValue(i))
}

for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  exampleFunctions[j]()
}

Summary

There we have the quick fix to how to use functions and closures inside a loop in JavaScript, if you want more like this be sure to check out some of my other posts!

I hope this post has helped, but before you go I highly recommend that you checkout Pluralsight if you are interested in improving your software engineering skills, such as React, JavaScript, or Typescript (and much more).

Not only does Pluralsight provide you with all the learning material you need but it also let's you learn in a fun, interactive way and gives you the ability to see your current progress and level in a certain skill via their Skill Assessment tool which can help you see what you need to learn next to keep improving!

Some graphics used on this post were made using icons from flaticon.