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?

8
  • So You are saying that You are familiar with java and presenting us javascript? :) JAVA !== javascript :) Don't ever call JS, JAVA AGAIN! :) Commented Mar 20, 2014 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 Commented Mar 20, 2014 at 18:39
  • By the way, for-in shouldnt be used for arrays Commented Mar 20, 2014 at 18:40
  • 1
    Mr. T - I pity the fool who calls javascript java! Commented Mar 20, 2014 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 Commented Mar 20, 2014 at 18:41

3 Answers 3

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]();
  }
}
Sign up to request clarification or add additional context in comments.

Comments

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...

Comments

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]();
         }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.