I am reading an article (JavaScript Closures for Dummies) and one of the examples is as follows.
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
When testList is called, an alert box that says "item3 undefined". The article has this explanation:
When the anonymous functions are called on the line
fnlist[j]();
they all use the same single closure, and they use the current value for i and item within that one closure (where i has a value of 3 because the loop had completed, and item has a value of 'item3').
Why does item have a value of 'item3'? Doesn't the for loop end when i becomes 3? If it ends shouldn't item still be 'item2'? Or is the variable item created again when testList calls the functions?
A local variable reference in the function or block in which it is declared overrides the same variable name in the larger scope. In programming languages with only two levels of visibility, local variables are contrasted with global variables.
The Complete Full-Stack JavaScript Course! A closure function gives access to the scope of an outer function from an inner function. It also allows private variables. Closure variables are stored in stack and heap.
Closures are frequently used in JavaScript for object data privacy, in event handlers and callback functions, and in partial applications, currying, and other functional programming patterns.
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.
You're close...
Why does item have a value of 'item3'? Doesn't the for loop end when i becomes 3?
Yes.
If it ends shouldn't item still be 'item2'?
Nope. This example is a little tricky. During the last iteration of the loop, i
is 2, but it references the 3rd element of the list
array, which is 3. In other words, item == 'item' + list[2] == 'item3'
Or is the variable item created again when testList calls the functions?
No, you were almost right the first time. I think you just missed that item[2]
has the value of 3.
The for loop within buildList completes before you do the following:
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
... therefore, by that time (when you call each function), the variable item
will be whatever was last assigned to it (i.e. "item3"), and i
will be 3
(as a result of the last i++
operation), and list[3]
is undefined
.
It's all to do with the fact that the loop completes before you call the closure'd function. To prevent this, you could create a new closure, like so:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push(
(function(item, i){
// Now we have our own "local" copies of `item` and `i`
return function() {
console.log(item + ' ' + list[i])
};
})(item, i)
);
}
return result;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With