Kelvin Zhao Kelvin Zhao - 4 months ago 18
Javascript Question

Looping and static num

I have a loop to run through my buttons to give it a hover state but I can't seem to know how to fix the 'i' inside the functions to when it's looped. Okay, that's a bad way of explaining what I'm trying to achieve, maybe the code will be clearer.



for ( i = 1; i < 4; i++ ) {
$( '#buttons #'+i ).hover( function() {
$( this ).text( i );
}, function() {
$( this ).text( 'Button' );
});
};

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="buttons">
<h1 id="1">Button</h1>
<h1 id="2">Button</h1>
<h1 id="3">Button</h1>
</div>





The hover state of each button is supposed to show 1, 2, 3 respectively.

Answer

If you'd like to do this in a way that is similar to your current code, it's very easy. Simply call a function in your loop, pass it the i variable, and set up the hover() callbacks inside that function. The only change to your code is the function call and function definition:

for ( i = 1; i < 4; i++ ) {
    setupHover( i );
}

function setupHover( i ) {
  $( '#buttons #' + i ).hover( function() {
	$( this ).text( i );
  }, function() {
	$( this ).text( 'Button' );
  });
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="buttons">
  <h1 id="1">Button</h1>
  <h1 id="2">Button</h1>
  <h1 id="3">Button</h1>
</div>

Why does this work? It's important to note that the two hover() callbacks are not called at the time your loop runs. They are called later, when you roll the mouse over the elements.

The problem in the original version is that the for loop has already run to completion, long before the hover() callbacks get called in response to mouse movement. So the i variable already has its final value of 4 before those callbacks run.

However, by calling a function inside the loop and passing i into that function, the called function captures a reference to the variable you pass in. Note that the i inside the setupHover() function is a separate variable from the i in your for loop. It's only coincidental that it has the same name, but it really is a separate variable that is unique to each invocation of the function.

Read up on "JavaScript closures" for more information.

You can also do the same thing in other ways, such as the technique in another answer where a function returns another function. There are cases where it's useful to have a function that returns another function. However if you simply need a closure, it is usually overkill.

Any function call can create a closure, so the only one you need is a simple replacement of the loop body with a function call. I recommend taking the simplest and easiest to understand approach.