0

I have the following code

<ul>
  <li>one</li>
  <li>two</li>        
  <li>three</li>
  <li>four</li>
</ul>

var lists = document.getElementsByTagName("li");

for(var i=0, len = lists.length; i< len; i++){
    lists[i].onmouseover = function(){
        console.log(i);
    }(i);
}

Expected result: when mouse over each li, I got 0 or 1 or 2 or 3 in the console, but I only got those number when refresh the page not in mouseover, anybody knows why?

James
  • 157
  • 1
  • 6

1 Answers1

4

The "calling parenthesis" (i) after the function expression execute the function immediately and assign its return value as event handler (which is undefined). Here is an example with a function declaration, which makes it easier to see (hopefully):

function foo(i) {
    console.log(i);
}

// in the loop
lists[i].onmouseover = foo(i);

See how foo is called and the return value is assigned to lists[i].onmouseover?

You have to return a function from the immediately invoked function expression:

lists[i].onmouseover = (function(i){
    return function() {
        console.log(i);
    };
}(i));

or with a function declaration:

function createHandler(i) {
    return function() {
        console.log(i);
    };
}

// in the loop
lists[i].onmouseover = createHandler(i);

More info: JavaScript closure inside loops – simple practical example

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Is the return statement necessary? Can it be like this: `code`(function(index){ lists[ index ].onmouseover = function(){ console.log(i); }; })(i);`code` Sorry, I don't konw how to format code in the comment. – James May 06 '13 at 07:06
  • Yes, you can do that too, you must moved the immediately executed function "one level up". It doesn't change anything though, it still works the same way. – Felix Kling May 06 '13 at 07:08
  • Thank you very much, Felix Kling, your replies are quite detailed, I think I got your point. – James May 06 '13 at 07:13
  • "must" should have been "just" in my comment. It does not matter where inside the loop the immediately executed function is, as long as it is there. Some people prefer to put it around the complete loop body (like you did in your example), others prefer to wrap it only around the code that really needs it. And again others (I would count myself to them) prefer to use a dedicated, named function, because it can make the code clearer. Anyways, happy coding! – Felix Kling May 06 '13 at 07:17
  • Yes, you are right, writing clear code is a good way, which sometimes could avoid memory leak(I just learned in some article), Happy coding too! – James May 06 '13 at 07:26