<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Ovi Maps API Example</title>
</head>
<body>
<button id="butt1" name="butt" type="button">Click Me!</button>
<button id="butt2" name="butt" type="button">Click Me!</button>
<button id="butt3" name="butt" type="button">Click Me!</button>
</body>
<script src="jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="foo.js" type="text/javascript" charset="utf-8"></script>
</html>
and...
$(document).ready(function() {
//alert("ready");
var myClickFunctions = new Array();
//add event handlers to all three buttons
for(var i=1;i<=3;i++){
myClickFunctions[i]=function(){
var index = i;
alert(index);
}
var buttonID = "#butt";
var button = $(buttonID + i);
button.click(myClickFunctions[i]);
}
});
Every button prints 4. Why is this and what is a good way to make each one print the value of i
in which the handler was created?
Read up on JavaScript closures and how they work. The fact is the i
in button.click(myClickFunctions[i]);
at the bottom will be 4 at the end. Remember the that var index=i isn't set when the function is declared, only when it is called. What you need to do is wrap the function in a closure like so:
myClickFunctions[i]=(function(i){
return function(){
var index = i;
alert(index);
}
})(i)
or better yet, do this:
//put this anywhere
function myClickFunctions(i){
return function(){
alert(i);
}
}
//and at the end:
button.click(myClickFunctions(i));
The myClickFunctions function will take the present value of i, and return a function with that value already set. That is the proper way to do this.
Your anonymous function that you are setting to myClickFunctions[i]
is creating a closure around i
. Closures close on the variable itself, not the value at the time the closure is made. So by the time that function actually runs, i
is 4 and therefore you will always get 4.
A simple fix is to invoke a function that returns a function, and captures the current value of i.
myClickFunctions[i] = (function(curI) {
return function() {
var index = curI;
alert(index);
};
})(i);
If that's confusing, then I recommend reading up on closures in JavaScript. They become second nature after a while.
Because you're assigning a new value to the same variable every time the function loops, therefore var Index is 4 when any button is clicked.
A quick approach to making each anchor tag print out its index would to attach something like the following:
$('a').click(function() {
var theAnchors = $('a');
for (i in theAnchors)
if (theAnchors[i] == this)
alert(i);
});
Only problem I can see with this is that I doubt the object equality comparison will only validate to true when the two DOM elements that are being compared are the exact same, but they could.
Moreover, though, what is the end goal that you are trying to accomplish here (as I'm sure making a page that harasses the user with alerts upon clicking any anchor is not your intended end goal).
The value of "i" when the loop ends is "4", so every when you click on a button the number that is going to show you is "4" because you are accessing the reference of "i" and the function is executing when you click on the button not during the loop.
If you want to get the number of "i" is the same as the button id, so i suggest doing this.
$(document).ready(function() {
//alert("ready");
var myClickFunctions = new Array();
//add event handlers to all three buttons
for(var i=1;i<=3;i++){
myClickFunctions[i]=function(){
var id = $(this).attr('id');
var index = id.replace('butt', '');
alert(index);
}
var buttonID = "#butt";
var button = $(buttonID + i);
button.click(myClickFunctions[i]);
}
});
精彩评论