JavaScript closure inside loops – simple practical example
It outputs this:
My value: 3
My value: 3
My value: 3
Whereas I'd like it to output:
My value: 0
My value: 1
My value: 2
The same problem occurs when the delay in running the function is caused by using event listeners:
… or asynchronous code, e.g. using Promises:
What’s the solution to this basic problem?
Well, the problem is that the variable i
, within each of your anonymous functions, is bound to the same variable outside of the function.
What you want to do is bind the variable within each function to a separate, unchanging value outside of the function:
Since there is no block scope in JavaScript - only function scope - by wrapping the function creation in a new function, you ensure that the value of "i" remains as you intended.
With the relatively widespread availability of the Array.prototype.forEach
function (in 2015), it's worth noting that in those situations involving iteration primarily over an array of values, .forEach()
provides a clean, natural way to get a distinct closure for every iteration. That is, assuming you've got some sort of array containing values (DOM references, objects, whatever), and the problem arises of setting up callbacks specific to each element, you can do this:
The idea is that each invocation of the callback function used with the .forEach
loop will be its own closure. The parameter passed in to that handler is the array element specific to that particular step of the iteration. If it's used in an asynchronous callback, it won't collide with any of the other callbacks established at other steps of the iteration.
If you happen to be working in jQuery, the $.each()
function gives you a similar capability.
ECMAScript 6 (ES6), the newest version of JavaScript, is now starting to be implemented in many evergreen browsers and backend systems. There are also transpilers like Babel that will convert ES6 to ES5 to allow usage of new features on older systems.
ES6 introduces new let
and const
keywords that are scoped differently than var
-based variables. For example, in a loop with a let
-based index, each iteration through the loop will have a new value of i
where each value is scoped inside the loop, so your code would work as you expect. There are many resources, but I'd recommend 2ality's block-scoping post as a great source of information.
Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let
but get the above wrong (they don't create a new i
each time, so all the functions above would log 3 like they would if we used var
). Edge 14 finally gets it right.
Try:
Edit (2014):
Personally I think @Aust's more recent answer about using .bind
is the best way to do this kind of thing now. There's also lo-dash/underscore's _.partial
when you don't need or want to mess with bind
's thisArg
.
Another way that hasn't been mentioned yet is the use of Function.prototype.bind
UPDATE
As pointed out by @squint and @mekdev, you get better performance by creating the function outside the loop first and then binding the results within the loop.
Using an Immediately-Invoked Function Expression, the simplest and most readable way to enclose an index variable:
This sends the iterator i
into the anonymous function of which we define as index
. This creates a closure, where the variable i
gets saved for later use in any asynchronous functionality within the IIFE.
Bit late to the party, but I was exploring this issue today and noticed that many of the answers don't completely address how Javascript treats scopes, which is essentially what this boils down to.
So as many others mentioned, the problem is that the inner function is referencing the same i
variable. So why don't we just create a new local variable each iteration, and have the inner function reference that instead?
Just like before, where each inner function outputted the last value assigned to i
, now each inner function just outputs the last value assigned to ilocal
. But shouldn't each iteration have it's own ilocal
?
Turns out, that's the issue. Each iteration is sharing the same scope, so every iteration after the first is just overwriting ilocal
. From MDN:
Important: JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.
Reiterated for emphasis:
We can see this by checking ilocal
before we declare it in each iteration:
This is exactly why this bug is so tricky. Even though you are redeclaring a variable, Javascript won't throw an error, and JSLint won't even throw a warning. This is also why the best way to solve this is to take advantage of closures, which is essentially the idea that in Javascript, inner functions have access to outer variables because inner scopes "enclose" outer scopes.
This also means that inner functions "hold onto" outer variables and keep them alive, even if the outer function returns. To utilize this, we create and call a wrapper function purely to make a new scope, declare ilocal
in the new scope, and return an inner function that uses ilocal
(more explanation below):
Creating the inner function inside a wrapper function gives the inner function a private environment that only it can access, a "closure". Thus, every time we call the wrapper function we create a new inner function with it's own separate environment, ensuring that the ilocal
variables don't collide and overwrite each other. A few minor optimizations gives the final answer that many other SO users gave:
Update
With ES6 now mainstream, we can now use the new let
keyword to create block-scoped variables:
Look how easy it is now! For more information see this answer, which my info is based off of.
With ES6 now widely supported, the best answer to this question has changed. ES6 provides the let
and const
keywords for this exact circumstance. Instead of messing around with closures, we can just use let
to set a loop scope variable like this:
val
will then point to an object that is specific to that particular turn of the loop, and will return the correct value without the additional closure notation. This obviously significantly simplifies this problem.
const
is similar to let
with the additional restriction that the variable name can't be rebound to a new reference after initial assignment.
Browser support is now here for those targeting the latest versions of browsers. const
/let
are currently supported in the latest Firefox, Safari, Edge and Chrome. It also is supported in Node, and you can use it anywhere by taking advantage of build tools like Babel. You can see a working example here: http://jsfiddle.net/ben336/rbU4t/2/
Docs here:
Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let
but get the above wrong (they don't create a new i
each time, so all the functions above would log 3 like they would if we used var
). Edge 14 finally gets it right.
Another way of saying it is that the i
in your function is bound at the time of executing the function, not the time of creating the function.
When you create the closure, i
is a reference to the variable defined in the outside scope, not a copy of it as it was when you created the closure. It will be evaluated at the time of execution.
Most of the other answers provide ways to work around by creating another variable that won't change the value for you.
Just thought I'd add an explanation for clarity. For a solution, personally, I'd go with Harto's since it is the most self-explanatory way of doing it from the answers here. Any of the code posted will work, but I'd opt for a closure factory over having to write a pile of comments to explain why I'm declaring a new variable(Freddy and 1800's) or have weird embedded closure syntax(apphacker).
What you need to understand is the scope of the variables in javascript is based on the function. This is an important difference than say c# where you have block scope, and just copying the variable to one inside the for will work.
Wrapping it in a function that evaluates returning the function like apphacker's answer will do the trick, as the variable now has the function scope.
There is also a let keyword instead of var, that would allow using the block scope rule. In that case defining a variable inside the for would do the trick. That said, the let keyword isn't a practical solution because of compatibility.
Here's another variation on the technique, similar to Bjorn's (apphacker), which lets you assign the variable value inside the function rather than passing it as a parameter, which might be clearer sometimes:
Note that whatever technique you use, the index
variable becomes a sort of static variable, bound to the returned copy of the inner function. I.e., changes to its value are preserved between calls. It can be very handy.
This describes the common mistake with using closures in JavaScript.
Consider:
For each time makeCounter
is invoked, {counter: 0}
results in a new object being created. Also, a new copy of obj
is created as well to reference the new object. Thus, counter1
and counter2
are independent of each other.
Using a closure in a loop is tricky.
Consider:
Notice that counters[0]
and counters[1]
are not independent. In fact, they operate on the same obj
!
This is because there is only one copy of obj
shared across all iterations of the loop, perhaps for performance reasons.
Even though {counter: 0}
creates a new object in each iteration, the same copy of obj
will just get updated with a
reference to the newest object.
Solution is to use another helper function:
This works because local variables in the function scope directly, as well as function argument variables, are allocated
new copies upon entry.
For a detailed discussion, please see JavaScript closure pitfalls and usage
The most simple solution would be,
Instead of using:
which alerts "2", for 3 times. This is because anonymous functions created in for loop, shares same closure, and in that closure, the value of i
is the same. Use this to prevent shared closure:
The idea behind this is, encapsulating the entire body of the for loop with an IIFE (Immediately-Invoked Function Expression) and passing new_i
as a parameter and capturing it as i
. Since the anonymous function is executed immediately, the i
value is different for each function defined inside the anonymous function.
This solution seems to fit any such problem since it will require minimal changes to the original code suffering from this issue. In fact, this is by design, it should not be an issue at all!
no array
no extra for loop
http://jsfiddle.net/7P6EN/
The main issue with the code shown by the OP is that i
is never read until the second loop. To demonstrate, imagine seeing an error inside of the code
The error actually does not occur until funcs[someIndex]
is executed ()
. Using this same logic, it should be apparent that the value of i
is also not collected until this point either. Once the original loop finishes, i++
brings i
to the value of 3
which results in the condition i < 3
failing and the loop ending. At this point, i
is 3
and so when funcs[someIndex]()
is used, and i
is evaluated, it is 3 - every time.
To get past this, you must evaluate i
as it is encountered. Note that this has already happened in the form of funcs[i]
(where there are 3 unique indexes). There are several ways to capture this value. One is to pass it in as a parameter to a function which is shown in several ways already here.
Another option is to construct a function object which will be able to close over the variable. That can be accomplished thusly
jsFiddle Demo
Here's a simple solution that uses forEach
(works back to IE9):
Prints:
JavaScript functions "close over" the scope they have access to upon declaration, and retain access to that scope even as variables in that scope change.
Each function in the array above closes over the global scope (global, simply because that happens to be the scope they're declared in).
Later those functions are invoked logging the most current value of i
in the global scope. That's the magic, and frustration, of closure.
"JavaScript Functions close over the scope they are declared in, and retain access to that scope even as variable values inside of that scope change."
Using let
instead of var
solves this by creating a new scope each time the for
loop runs, creating a separated scope for each function to close over. Various other techniques do the same thing with extra functions.
(let
makes variables that are block scoped instead of function scoped. Blocks are denoted by curly braces, but in the case of the for loop the initialization variable, i
in our case, is considered to be declared in the braces.)
After reading through various solutions, I'd like to add that the reason those solutions work is to rely on the concept of scope chain. It's the way JavaScript resolve a variable during execution.
In the initial code:
When funcs
gets executed, the scope chain will be function inner -> global
. Since the variable i
cannot be found in function inner
(neither declared using var
nor passed as arguments), it continues to search, until the value of i
is eventually found in the global scope which is window.i
.
By wrapping it in an outer function either explicitly define a helper function like harto did or use an anonymous function like Bjorn did:
When funcs
gets executed, now the scope chain will be function inner -> function outer
. This time i
can be found in the outer function's scope which is executed 3 times in the for loop, each time has value i
bound correctly. It won't use the value of window.i
when inner executed.
More detail can be found here
It includes the common mistake in creating closure in the loop as what we have here, as well as why we need closure and the performance consideration.
With new features of ES6 block level scoping is managed:
The code in OP's question is replaced with let
instead of var
.
I'm surprised no one yet has suggested using the forEach
function to better avoid (re)using local variables. In fact, I'm not using for(var i ...)
at all anymore for this reason.
// edited to use forEach
instead of map.
First of all, understand what's wrong with this code:
Here when the funcs
array is being initialized, i
is being incremented, the funcs
array is initialized and the size of func
array becomes 3, so i = 3,
.
Now when the funcs[j]()
is called, it is again using the variable i
, which has already been incremented to 3.
Now to solve this, we have many options. Below are two of them:
We can initialize i
with let
or initialize a new variable index
with let
and make it equal to i
. So when the call is being made, index
will be used and its scope will end after initialization. And for calling, index
will be initialized again:
Other Option can be to introduce a tempFunc
which returns the actual function:
This question really shows the history of JavaScript! Now we can avoid block scoping with arrow functions and handle loops directly from DOM nodes using Object methods.
We will check , what actually happens when you declare var
and let
one by one.
Now open your chrome console window by pressing F12 and refresh the page.
Expend every 3 functions inside the array.You will see an property called [[Scopes]]
.Expand that one. You will see one
array object called "Global"
,expand that one. You will find a property 'i'
declared into the object which having value 3.
Conclusion:
Now replace the 'var'
with 'let'
Do the same thing, Go to the scopes . Now you will see two objects "Block"
and "Global"
. Now expand Block
object , you
will see 'i' is defined there , and the strange thing is that , for every functions , the value if i
is different (0 , 1, 2).
Conclusion:
When you declare variable using 'let'
even outside the function but inside the loop , this variable will not be a Global
variable , it will become a Block
level variable which is only available for the same function only.That is the reason , we
are getting value of i
different for each function when we invoke the functions.
For more detail about how closer works , please go through the awesome video tutorial https://youtu.be/71AtaJpJHw0
I prefer to use forEach
function, which has its own closure with creating a pseudo range:
That looks uglier than ranges in other languages, but IMHO less monstrous than other solutions.
The reason your original example did not work is that all the closures you created in the loop referenced the same frame. In effect, having 3 methods on one object with only a single i
variable. They all printed out the same value.
You could use a declarative module for lists of data such as query-js(*). In these situations I personally find a declarative approach less surprising
You could then use your second loop and get the expected result or you could do
(*) I'm the author of query-js and therefor biased towards using it, so don't take my words as a recommendation for said library only for the declarative approach :)
And yet another solution: instead of creating another loop, just bind the this
to the return function.
By binding this, solves the problem as well.
Many solutions seem correct but they don't mention it's called Currying
which is a functional programming design pattern for situations like here. 3-10 times faster than bind depending on the browser.
See the performance gain in different browsers.
Use closure structure, this would reduce your extra for loop. You can do it in a single for loop:
Your code doesn't work, because what it does is:
Now the question is, what is the value of variable i
when the function is called? Because the first loop is created with the condition of i < 3
, it stops immediately when the condition is false, so it is i = 3
.
You need to understand that, in time when your functions are created, none of their code is executed, it is only saved for later. And so when they are called later, the interpreter executes them and asks: "What is the current value of i
?"
So, your goal is to first save the value of i
to function and only after that save the function to funcs
. This could be done for example this way:
This way, each function will have it's own variable x
and we set this x
to the value of i
in each iteration.
This is only one of the multiple ways to solve this problem.
COUNTER BEING A PRIMITIVE
Let's define callback functions as follows:
After timeout completes it will print 2 for both. This is because the callback function accesses the value based on the lexical scope, where it was function was defined.
To pass and preserve the value while callback was defined, we can create a closure, to preserve the value before the callback is invoked. This can be done as follows:
Now what's special about this is "The primitives are passed by value and copied. Thus when the closure is defined, they keep the value from the previous loop."
COUNTER BEING AN OBJECT
Since closures have access to parent function variables via reference, this approach would differ from that for primitives.
So, even if a closure is created for the variable being passed as an object, the value of the loop index will not be preserved. This is to show that the values of an object are not copied whereas they are accessed via reference.
This is a problem often encountered with asynchronous code, the variable i
is mutable and at the time at which the function call is made the code using i
will be executed and i
will have mutated to its last value, thus meaning all functions created within the loop will create a closure and i
will be equal to 3 (the upper bound + 1 of the for
loop.
A workaround to this, is to create a function that will hold the value of i
for each iteration and force a copy i
(as it is a primitive, think of it as a snapshot if it helps you).
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?