0

I have this sample code:

function(){
  var events = [];
  var pages = ["a", "b", "c"];
  for(var pageIndex in pages){
    var pageName = pages[pageIndex];
    var e = function(){
      console.info(pageName);
    };
    events.push(e);
  }
  for(var eventIndex in events){
   console.info("index: " + eventIndex);
   events[eventIndex]();
  }
}

Output:

index: 0 
c 
index: 1 
c 
index: 2 
c 

Desired output:

index: 0 
a 
index: 1 
b 
index: 2 
c 

Is there a standard practice for this?

Spina
  • 8,986
  • 7
  • 37
  • 36
  • So You are saying that You are familiar with java and presenting us javascript? :) JAVA !== javascript :) Don't ever call JS, JAVA AGAIN! :) – Mr.TK Mar 20 '14 at 18:38
  • @Mr.TK he didn't, he really is experienced in Java...I think he was trying to say that he was new at JS – howderek Mar 20 '14 at 18:39
  • By the way, [for-in shouldnt be used for arrays](http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript) – hugomg Mar 20 '14 at 18:40
  • 1
    Mr. T - I pity the fool who calls javascript java! – Sten Muchow Mar 20 '14 at 18:41
  • It seems you are just referencing the object with e which are then updatedon the next iteration which is why you have c three times , try creating a new object with the value of the current iteration and adding it to list – c0d3junk13 Mar 20 '14 at 18:41
  • :) Let the Spina defend for himself :) Spina, are You from Poland? Cause i've often hear people in our country calling JS as JAVA. :) – Mr.TK Mar 20 '14 at 18:42
  • @Sten Muchow :D lol That was great. ;D I regret i didn't came up with this thus that was the reason i've chosen this nickname. ;D (And those are my initials as well ) – Mr.TK Mar 20 '14 at 18:43
  • Hi Mr. TK I understand that Java and Javascript are different languages. Thanks for the reminder. My sentence about Java was an incomplete thought. I was going to complain about prototype based inheritance, but then decided it wasn't relevant. – Spina Mar 21 '14 at 00:04

3 Answers3

1

Welcome to closures in javascript, you need to wrap the function in an IIFE or immediately invoked function expression which creates a closure and saves the state in its scope:

(function(){

  var events = [];
  var pages = ["a", "b", "c"];

  for(var pageIndex in pages){
    var pageName = pages[pageIndex];
    var e = (function(pageName){
      return function() {console.info(pageName);};
    }(pageName));
    events.push(e);
  }

  for(var eventIndex in events){
   console.info("index: " + eventIndex);
   events[eventIndex]();
  }
}());

Copy and paste it into the console debugger to test...

Sten Muchow
  • 6,623
  • 4
  • 36
  • 46
1

Each e function that you create is a closure that accesses the external variable pageName from the enclosing code. The pageName that it will see is the value at the time the function is run. So at the end of your loop pageName is "c", so that is what all of the functions will use when they are executed.

You can fix this by wrapping your function in the following way, which will essentially bind the current value of pageName to the function you create:

function(){
  var events = [];
  var pages = ["a", "b", "c"];
  for(var pageIndex in pages){
    var pageName = pages[pageIndex];
    var e = (function(data) {
      return function() {
        console.info(data);
      };
    })(pageName);
    events.push(e);
  }
  for(var eventIndex in events){
   console.info("index: " + eventIndex);
   events[eventIndex]();
  }
}
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
0

I found the answer here. I need to wrap my function in another function. How nifty.

    Template.index.test = function(){
         var events = [];
         var pages = ["a", "b", "c"];
         for(var pageIndex in pages){
           var pageName = pages[pageIndex];
           var e = function(pageName) {
             return function(){
               console.info(pageName);
             };
           }(pageName);
           events.push(e);
         }
         for(var eventIndex in events){
           console.info("index: " + eventIndex);
           events[eventIndex]();
         }
    }
Community
  • 1
  • 1
Spina
  • 8,986
  • 7
  • 37
  • 36