In this post, I am going to explain the classic “Javascript Last Value” problem better than anyone else on the Internet. Why such a bold claim? Because no-one else goes deep enough in their explanations. I’m going deep and I’m going to use pictures to enable you to visualise what is going on.
A pre-requisite to this post is an understanding of self-invoking functions. If you are unfamiliar with this simple Javascript construct, this article looks about as good as any.
So, what is the Last Value problem? This occurs where functions are declared in a loop. When they are then each executed at a later time, the last value assigned to the “incrementing loop variable” is displayed.
I’ve created a plunk to demonstrate.
Click the Run button and then click the button with the text Click for Young Players Error
You will see the integer 5 displayed on separate lines.
Most programmers new to Javascript look at this code and expect to see 0,1,2,3,4,5 displayed. As we saw, 5,5,5,5,5 was displayed. Why? Time to start explaining stuff…
Lets look at the code which has led to that and examine what is going on.
At line 15 of the script.js file of the plunk, there is a loop which is pushing an anonymous function onto the array called loadWithLogWrites in each iteration of the loop. Don’t worry too much about all the other code around it, as that is just hooking up click-events on the buttons so we can see what’s going on.
Lines 21 to 25 show each of those functions being invoked, the results of each invocation being added to the div called ouptputDiv.
A couple of things to note:
- The first thing I want to note is that each of those functions is a separate function. It’s not the same function repeated. Functions are objects and each item in that array is a separate function object (an anonymous function). That is important to realise.
- The next important thing to note here is the fact that Javascript does not have block scope. It has function scope. For example, if the following statements are all in the same function,
1will be successfully logged, even thoughvalis declared and assigned a value inside the block scope of the if statement:if(0===0) { var val = 1; } console.log(val); // this is fine and 1 is logged,If the variable is not inside a function, it is in the
Globalnamespace. What does that mean for our example? Unlike C, C++, C# etc. the variableiis not scoped to theforloop. It is a variable of theGlobalnamespace. To confirm that, go to the plunk, and movevar i = 0to a location out of and above theforloop.var i = 0 for (; i < 5; i += 1) { loadWithLogWrites.push(function() { return '<div>' + i + '</div>'; }); }You’ll find that nothing has changed. As I said, if
iis not in a function,iis scoped to theGlobalnamespace.
With those points in mind, we can see that the functions which have been pushed onto the loadWithLogWrites array all have access to i. Not because it is referenced inside each function; but because it is scoped to the Global namespace and can therefore be referenced from within each function. The Global namespace is in the scope chain of all the functions. I’ve done up a diagram which I want to use to consolidate in your minds the points I have made up until now:

Figure 1 – shows each of the anonymous functions as separate objects, all within the Global namespace
Now to the explanation of why 5s are displayed. It’s really quite simple if we take into account all of the points I made above. Each function has access to i. By the time any of them are invoked (starting on line 21), they have a value of 5. It is the same Global variable i, which they have access to, and that variable was incremented in the for loop to 5.
To elaborate (I like to ram home a point), consider the 2nd function pushed onto the array. At the instance it was pushed onto the array, i had a value of 1. However, i is scoped globally and not to the for loop. By the time that 2nd function is invoked on line 22, i has a value of 5.
So, how do we change the code such that when we click a button, the values 0,1,2,3,4 are displayed? Go back to the plunk and click the button with the text Click for Doing It Properly. You should see some lines of text, starting with item: 0 and can still access global i: 5. Figure 2 pictorially shows what is going on.
Looking at Figures 1 and 2, I have used different colours for a very good reason (not just to look pretty). Each colour represents a discrete scope. In Figure 1, you can see that each function which is added to the loadWithLogWrites array has its own separate scope. And as explained above, each of those functions has access to the variable i, which is in the Global (light green) scope.
In Figure 2, something very different is happening. The functions which are each being pushed onto the loadWithLogWrites array are being immediately self-invoked. They each also have an inner function which is the one that returns the div (similar to the functions in Figure 1).
And the variable i which is being passed to those self-invoking functions is being created anew as the item parameter inside those functions when they are being self-invoked. This creates a closure which effectively traps that item parameter and its value at the point in time at which it is created. And it is created during the loop.
So, each of the inner functions of the outer functions, which are pushed onto loadWithLogWrites, has access to the
itemvariable andivariable
The difference being, the i variable is still in the Global (light green) scope, whereas each discrete item variable is only available in each of the scopes created during the loop. To clarify from a different perspective, in Figure 2, the item variable in the red (outer) and purple (inner) scopes is not available to the light blue (outer) and dark green (inner) scopes (or any of the other scopes for that matter).
Important Final Thoughts
One of the reasons I went through such pains to understand this is because when I was learning JavaScript, there was a statement in a book which I just could not marry up with my understanding of what was going on. That statement was:
Like most modern programming languages, JavaScript uses lexical scoping. This means that functions are executed using the variable scope that was in effect when they were defined, not the variable scope that is in effect when they are invoked.
I thought that functions were executed using the variable scopes that were in effect when they were invoked. But after that in-depth analysis, it became clear to me how the book was correct and that my understanding was wrong.
The Figure 1 scenario is simple. Those variable scopes were all in effect when the functions were defined. Figure 2 took a bit longer to digest. The inner functions are executed using the variable scope which is created when the outer functions are self-invoked. When those are self-invoked, it is at that point that the inner functions are defined. And when they are finally executed in lines 43 – 47 of the plunk, the relevant variable scope is that scope which was in effect when those functions were defined.

0 Comments.