Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are local variables referenced in closures? [duplicate]

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?

like image 406
hekevintran Avatar asked Jun 01 '09 02:06

hekevintran


People also ask

How are local variables referenced?

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.

Where are closure variables stored?

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.

What are closures few common uses for closures?

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.

How do JavaScript closures work?

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.


2 Answers

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.

like image 188
Kenan Banks Avatar answered Oct 30 '22 15:10

Kenan Banks


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;
}
like image 22
James Avatar answered Oct 30 '22 14:10

James