I need help with doing a JavaScript closure on the following code. I am not full
ID: 3828391 • Letter: I
Question
I need help with doing a JavaScript closure on the following code. I am not fully understanding how to do closure. Below is the problem statement.
This one is a real gotcha for many people, so you need to understand it. Be very careful if you are defining a function within a loop: the local variables from the closure do not act as you might first think.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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]();
}
}
The line result.push( function() {alert(item + ' ' + list[i])} adds a reference to an anonymous function three times to the result array. If you are not so familiar with anonymous functions think of it like:
?
1
2
pointer = function() {alert(item + ' ' + list[i])};
result.push(pointer);
Note that when you run the example, "item3 undefined" is alerted three times! This is because just like previous examples, there is only one closure for the local variables for buildList. 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').
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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]();
}
}
Explanation / Answer
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;
}
// The functons are always executed at runtime.. Hence.. When you build the list.. You just say that each function need to alert value of item and list[i], which are referred from the parent scope.. The exact value of parent variables are determined at runtime.
So In:
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
The function can always access item value and list[i] value.. because they are defined in parent scope..
Now once you complete building your list.. Your i value becomes 4, and thus list[i] becomes undefined..
So that is why when you run these functions from testList(), they give you undefined..
I hope you got the problem, that the parent variables have moved and the functions are still trying to ue them..
So, To resolve them.. We need somehow to make those parent variables constant.. so that they don't change when we run the functions..
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
// self calling function.. executes immediately..
// as soon as this runs.. it sets the internal variables
// values(item and l).. And This self executing function
// returns the reference of internal function.. So later
// we call the function from testList.. We basically are
// calling the Internal returned function.. and that function
// refers to the parent variables item and l.. which we have
// set earlier and will not change.. because self executing
// function is not called again..
var add = (function () { // function 1
var item = 'item' + list[i];
var l = list[i];
return function () { // function 2
alert(item + ' ' + l);
}
})();
result.push(add);
}
return result;
}
fucntion 1 is self executing and hence runs just once.. at the time of defining it itself.. It doesn't wait for someone to call it.. Hence as soon as it runs.. it sets the variables item and l in function 1, and then it returns reference of function 2.. Now from test function we just call function 2... We never directly call function 1, due to which the variables in function 1 remains unchanged.. and when we call functions from test function.. individual function use their own parent's item and l value, so it shows correctly.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.