Consider the following code:
<!DOCTYPE html>
<html>
<head>
<script>
function timedText()
{
var x=document.getElementById('txt');
var t = new Array();
t[1] = setTimeout( function(){x.value="2 seconds"}, 2000 );
t[2] = setTimeout( function(){x.value="4 seconds"}, 4000 );
t[3] = setTimeout( function(){x.value="6 seconds"}, 6000 );
}
function timedTextArr()
{
var x=document.getElementById('txt');
var t = new Array();
for( var i = 0 ; i < 3 ; i++ ) {
t[i] = setTimeout( function(){x.value=i*2+" seconds"}, i*2000 );
}
}
</script>
</head>
<body>
<form>
<input type="text" id="txt" />
<input type="button" value="Display timed text!" onclick="timedText()" />
<input type="button" value="Display timed text Arr!" onclick="timedTextArr()" />
</form>
<p>Click on the button above. The input field will tell you when two, four, and six seconds have passed.</p>
</body>
</html>
Function timedText()
works, but timedTextArr()
doesn't. Both functions assign return values from setTimeout()
to array elements. But in the for()
loop, only the last timer works... and it works three times.
Is this a bug?
This is not a bug, have a look at what closures are in Javascript.
Basically in your for loop the function
function(){x.value=i*2+" seconds"}
only "sees" one instance of the i variable.
So once the loop is over, i is equal to 3, so it is 3 for all functions.
You need to wrap the call in another anonymous function to create a scope, like this:
t[i] = setTimeout( (function(i){ return function(){x.value=i*2+" seconds"}})(i), i*2000 );
The outer function will create a new scope, and inside it i will be equal to the value of i in the loop and stay like this. You can try it out there: http://jsfiddle.net/6b68E/
The i
in your function refers to the i
from the loop, which is 6
by the time any of the timeouts fire. You need to add a closure/scope:
for( var i = 0 ; i < 3 ; i++ ) {
(function(){ // create a closure (new scope)
var _i = i; // make a local copy of `i` from the outer scope
t[i] = setTimeout( function(){x.value=_i*2+" seconds"}, i*2000 );
})();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With