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.

asked Aug 17, 2012 at 9:41

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
 }
pimvdb
155k80 gold badges313 silver badges358 bronze badges
answered Aug 17, 2012 at 9:43
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);
answered Aug 17, 2012 at 9:43

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.

answered Aug 17, 2012 at 10:03

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);
 }
answered Aug 17, 2012 at 9:43

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

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.