views:

69

answers:

3

There are two versions, supposedly when the user click the first link, it will alert "1", and the second link, "2", etc:

Version 1:

<a href="#" id="link1">click me</a>
<a href="#" id="link2">click me</a>
<a href="#" id="link3">click me</a>
<a href="#" id="link4">click me</a>
<a href="#" id="link5">click me</a>

<script type="text/javascript">  

  for (i = 1; i <= 5; i++) {
    document.getElementById('link' + i).onclick = (function() {
      return function() {
        var n = i;
        alert(n); 
        return false;
      }
    })();
  }

</script>

Version 2:

<a href="#" id="link1">click me</a>
<a href="#" id="link2">click me</a>
<a href="#" id="link3">click me</a>
<a href="#" id="link4">click me</a>
<a href="#" id="link5">click me</a>

<script type="text/javascript">  

  for (i = 1; i <= 5; i++) {
    document.getElementById('link' + i).onclick = (function() {
      var n = i;
      return function() {
        alert(n); 
        return false;
      }
    })();
  }

</script>

Version 1 will not work. Version 2 will. I think I know the reason why, but would like to compare with other people's explanations as to why version 1 doesn't work.

+4  A: 

Version 1 does not work because there's a common variable "i" (a global variable in this case, because you forgot var) that is shared by every "click" handler function the loop creates.

In the second version, you create a new lexical scope with the little wrapper function. That gives each "click" handler it's very own private "i".

Pointy
+2  A: 

In the second example you create a var n = i; it makes i value scoped inside the onclick function. While at the first one the onclick function still uses global value of i

I'd suggest this usage instead:

  for (i = 1; i <= 5; i++) {
    document.getElementById('link' + i).onclick = (function(i) {
      return function() {
        alert(i); 
        return false;
      }
    })(i);
  }

In this case you'll get the same behaviour since i will be the local variable for onclick function as it's an argument.

fantactuka
A: 

First does not work because: i is the part of each closure. After 5 iterations now i is 6 due to postfix increment operator. Each time when event handler is invoked it gets the value of i from its closure scope that is always 6.

Second part works: because each closure makes a copy of i in n, n is part of each closure.

Shoaib
from looking at version 1, doesn't it making a new copy of `i` every time too?
動靜能量
No. In version 1. it is not making copies while iterating foreach. But it makes copy when clicked.
Shoaib