As one of the earliest posts on my blog, way back in 2006, I talked about the problem with variable binding inside the context of loops. If you didn't understand variable hoisting (as I didn't at the time), configuring event handlers inside a FOR loop could quickly lead to unexpected and frustrating behaviors.
When I started using jQuery, shortly thereafter, I was super pumped-up to find out that the .each() method could alleviate some of these variable hoisting problems. By using a callback for each "loop iteration," jQuery's each() method bypassed the hoisting problem by providing each iteration with its own scope (and hoisting context).
This same sandboxing effect can be used outside of jQuery through the use of self-executing function expressions. Essentially, you can create an anonymous function within the block of a FOR loop; then, for each iteration, invoke the anonymous function, defining the relevant context and passing in the index values.
In the following demo, we'll define a number of methods that bind to the "current" value of "i." Then, we'll execute those methods after the loop to see if the iteration-specific value-binding took place.
As you can see, we have a simple FOR loop iterating from zero to four. For each loop, we define and then invoke an anonymous function block. In order to maintain the proper execution context, we're using the call() method to explicitly set the "this" value used within the anonymous function. As part of the anonymous function invocation, we're also passing in i - the value of the loop iteration index. This creates an iteration sandbox while also binding the iteration index to the invocation parameter of the self-executing function.
As a control, we're also logging the value of, "j," which is bound to the value, "i," at the FOR-loop level. Since "j" is not being passed into the self-executing function, it will fall victim to the hoisting effect. And, in fact, when we run the above code, we get the following console output:
0 - 4
1 - 4
2 - 4
3 - 4
4 - 4
As you can see, each function definition was bound to the appropriate value of "i." And, the value of "j" was bound to the last known value of "i".
The LET keyword can do a bit more than what I described; but, the primary function of the LET keyword can be somewhat replicated through the use of self-executing function blocks. Since the self-executing function blocks are invoked for each iteration of our FOR loop, it provides both an execution sandbox and an opportunity to bind iteration variables to invocation arguments.
Want to use code from this post? Check out the license.