Reputation: 570
I am using jQuery to generate and add a random amount of Clouds to the Header of the page and move them left on the specified interval. Everything is working fine, execpt the interval only runs once for each Cloud and not again. Here is my code:
if(enableClouds) {
var cloudCount = Math.floor(Math.random() * 11); // Random Number between 1 & 10
for(cnt = 0; cnt < cloudCount; cnt++) {
var cloudNumber = Math.floor(Math.random() * 4);
var headerHeight = $('header').height() / 2;
var cloudLeft = Math.floor(Math.random() * docWidth);
var cloudTop = 0;
var thisHeight = 0;
var cloudType = "one";
if(cloudNumber == 2) {
cloudType = "two";
}else if(cloudNumber == 3) {
cloudType = "three";
}
$('header').append('<div id="cloud' + cnt + '" class="cloud ' + cloudType + '"></div>');
thisHeight = $('#cloud' + cnt).height();
headerHeight -= thisHeight;
cloudTop = Math.floor(Math.random() * headerHeight);
$('#cloud' + cnt).css({
'left' : cloudLeft,
'top' : cloudTop
});
setInterval(moveCloud(cnt), 100);
}
function moveCloud(cloud) {
var thisLeft = $('#cloud' + cloud).css('left');
alert(thisLeft);
}
}
Any help is appreciated!
Upvotes: 0
Views: 163
Reputation: 27529
Engineer gave you the code you need. Here's what's happening.
The setInterval
function takes a Function object and an interval. A Function object is simply an object that you can call, like so:
/* Create it */
var func = function() { /* ... blah ... */};
/* Call it */
var returnVal = func(parameters)
The object here is func
. If you call it, what you get back is the return value.
So, in your code:
setInterval(moveCloud(cnt), 100);
you're feeding setInterval
the return value of the call moveCloud(cnt)
, instead of the the function object moveCloud
. So that bit is broken.
An incorrect implementation would be:
for(cnt = 0; cnt < cloudCount; cnt++) {
/* ... other stuff ... */
var interval = setInterval(function() {
moveCloud(cnt);
}, 100);
}
Now, you're feeding it a function object, which is correct. When this function object is called, it's going to call moveCloud
. The problem here is the cnt
.
What you create here is a closure. You capture a reference to the variable cnt
. When the function object that you passed to setInterval
is called, it sees the reference to cnt
and tries to resolve it. When it does this, it gets to the variable that you iterated over, looks at its value and discovers that it is equal to cloudCount
. Problem is, does not map on to a Cloud that you created (you have clouds 0 to (cloudCount -1)), so at best, nothing happens, at worst, you get an error.
The right way to go is:
setInterval((function(i){
return function(){
moveCloud(i);
};
})(cnt), 100);
This uses an 'immediate function' that returns a function. You create a function:
function(i){
return function(){
moveCloud(i);
};
}
that returns another function (let's call it outer
) which, when called with a value i
, calls moveCloud
with that value.
Then, we immediately call outer
with our value cnt
. What this gives us is a function which, when called, calls moveCloud
with whatever the value of cnt
is at this point in time. This is exactly what we want!
And that's why we do it that way.
Upvotes: 2
Reputation: 48793
This is the way to go:
setInterval((function(i){
return function(){
moveCloud(i);
};
})(cnt), 100);
Upvotes: 2