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>
精彩评论