Blog / Quick-fixes

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 MaygerWill Mayger
August 05, 2021
Article

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!

Foxi - Budget Planner & Tracker

Foxi

Budget Planner & Tracker

More money in your pocket by the end of the month.

Free to use and no account needed.

Get started now.

Get the app

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

Latest Posts

Learn React, JavaScript and TypeScript

Learn React, JavaScript and TypeScript

Join the platform that top tier companies are using.
Master the skills you need to succeed as a software engineer and take your career to the next level with Pluralsight.

Start here

Become an expert in ReactJS, TypeScript, and JavaScript.

Here you will find my personal recomendations to you, for full disclosure I earn a small commission from some of these links, but I only recommend what I trust and personally use.

Good things are coming, don't miss out!

Good things are coming, don't miss out!

Follow me on Twitter to stay up to date and learn frontend, React, JavaScript, and TypeScript tips and tricks!

Are you a novice, intermediate or expert react engineer?

Find out here by taking my fun, interactive, quick quiz which takes approximately 1 - 3 minutes. How well will you will do?

Foxi - Budget Planner & Tracker

Foxi

Budget Planner & Tracker

More money in your pocket by the end of the month.

Free to use and no account needed.

Get started now.

Get the app