开发者

What am I doing wrong on this simple Closure

It maybe sleep deprivation but I cannot understand why this isn't working. I want the onclick to return the value of i from a for loop that created the element and applied the event handler. Have put it in a closure and it is still turning the max number of the iterator.

window.onload = function(){
  var arbitrary_amount = 100;
  var the_list = document.getElementsByTagName('ul')[0];
  
  for(var i = 0; i < arbitrary_amount; i++){
    var natural_index = i + 1;
    var list_item = document.createElement('li');
    var inner_link = document.createElement('a');
    inner_link.setAttribute('href', '#');
    inner_link.innerHTML = "Link "+natural_index;
    
    inner_link.onclick = function(){
      return function(link_num){
        alert('You clicked link '+lin开发者_C百科k_num);
      }(i);
    };
    
    list_item.appendChild(inner_link);
    the_list.appendChild(list_item);
  }
  
  
};


you are using the closure in the wrong way...i can't give you a guru type answer as to what was actually happening but here is a working (didn't test it) closure:

inner_link.onclick = (function(link_num){
   return function(){
       alert('You clicked link '+link_num);
   };
})(i);


You can try with:

window.onload = function(){
  var arbitrary_amount = 100;
  var the_list = document.getElementsByTagName('ul')[0];

  for(var i = 0; i < arbitrary_amount; i++){
    (function(){var natural_index = i + 1;
    var list_item = document.createElement('li');
    var inner_link = document.createElement('a');
    inner_link.setAttribute('href', '#');
    inner_link.innerHTML = "Link "+natural_index;

    inner_link.onclick = function(){
      return function(link_num){
        alert('You clicked link '+link_num);
      }(i);
    };

    list_item.appendChild(inner_link);
    the_list.appendChild(list_item);})();
  }


};


It's because each closure you create for the onclick handler shares the same environment. When the onclick callback function is executed, each one refers to the last value of i.

There are already various solutions out, so I won't repeat it here, but the idea is to create additional closures that do not share the same environment.

It's a common mistake. Checkout this MDC article for more insights.


Your code works correctly for me in Firefox 3.5.5 and Chrome 4.0.249.64.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">


<head>


<title>Just testing</title>


<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />


</head>
<body>



<div id="test1">
Testing
</div>




<script type="text/javascript">


//  self-invoking function


(function makeHR(){
      var newHR = document.createElement('hr');
      document.getElementById('test1').appendChild(newHR);
})();





function makeLink(j){


      var link =document.createElement("a");


  link.innerHTML ="<br>Link test " +j;


  link.setAttribute('href', '#');

  link.onclick = (function(link_num){


   return function(){


   alert('You clicked link '+link_num);

   };


  })(j);

  document.body.appendChild(link);
}


for (var i=1; i<4; i++) {

   makeLink(i);

}


</script>


</body>

</html>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜