0

I have a problem getting the value of 'name' displayed with the following:

   for (var name in array) {
        var hoverIn = function() {
                  alert(name);
        };

        var hoverOut = function() {
        };

        thing.hover(hoverIn, hoverOut);

   }

What I get is an alert window with the last value of name. Clearly I am doing something wrong and I suspect it's a simple fix. Can anyone help?

Thanks.

4 Answers 4

7

It's closure problem, name, after that iteration is the last name in array, and callback for hovers isn't executed right away when the iteration happens, thus when the hover function is actually executed, name will always be the last in array.

You need to use IEFE (Immediately executed function expression):

   for (var name in array) {
        // pass in name to the anonymous function, and immediately
        // executes it to retain name when the particular iteration happens
        var hoverIn = (function(name) {
             return function() {
                  alert(name);
             }
        })(name); // if you notice, the pattern is (function(name) {})(name) 
                  // the first () creates an anonymous function, the (name) 
                  // executes it, effectively passing name to the anon fn

        var hoverOut = (function(name) {
            // same pattern if you need to re-use name inside here, otherwise just
            // function() { } should suffice
        })(name);

        thing.hover(hoverIn, hoverOut);

   }

To avoid duplicates of (function() { })() (which honestly is getting tiring to look at), you could also, as @pimvdb pointed out, wrap the whole body in a closure:

   for (var name in array) {
        (function(name) {
           var hoverIn = function() {
               alert(name);
           }

           var hoverOut = function() {
           }

           thing.hover(hoverIn, hoverOut);
        })(name); // closure of for loop body

   }
Sign up to request clarification or add additional context in comments.

2 Comments

You should not pass var to the function! Why do you create a copy of the name?
As a side note, one could also just wrap the whole for loop body.
0

Add a variable inside the loop

var thisName = name;

and then use that in your function

alert(thisName);

Comments

0

You have two ways of dealing with this problem.

The first thing to know is that scope only happens at function level, not within loops in javascript. If you set a variable within a function from an outside source and don't execute it right away,the variable will be changed over the course of your loop.

You can solve this by closing other the variable:

var names = ["john","paul","george","ringo"];
var store = {};

//this function receives the data as a parameter
//so it will be a safe copy.

function createFunc(name){
     //just return a function that will alert the name.
    return function(){
       alert(name);
    }
}
for (var i in names) {

        var hoverIn = createFunc(names[i]);

        store[names[i]]=hoverIn;

}
store["john"]();

The other way is to create an anonymous function that executes right away within the loop:

var names = ["john","paul","george","ringo"];
var store = {};

for (var i in names) {
   //the function receives the i as a parameter
   //and executes, so n is a safe copy of i
  (function(n){

    var hoverIn = function(){
        alert(names[n]);
    }

    store[names[n]]=hoverIn;

  })(i);

}
store["john"]();

Everything is a problem related to closure. Look at wikipedia for more info.

Comments

-2

You should create closure:

 for (var name in array) {
        var hoverIn = (function() {
              return function() {
                  alert(name);
              };
        }());

        var hoverOut = function() {
        };

        thing.hover(hoverIn, hoverOut);
   }

8 Comments

That would not fix anything: he already had a closure over var name. A closure closes over variables, not values. That's why it did not work.
Here, name still refers to the one of the for loop, so it doesn't really change anything.
@MennovandenHeuvel You dont understand what closure means=) Check this fiddle - jsfiddle.net/yHSpg. And then will have realized that was wrong!
@Serjio: No, you're not fully understanding it. Try the infamous setTimeout example of your demo: jsfiddle.net/yHSpg/1.
I respect your opinion but it simply does not work. Here's a demo of your solution: jsfiddle.net/Fym87. It alerts 1 twice, not 0 and 1.
|

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.