JavaScript timers – using functions and scope
This article is also available in Russian.
Today I thought I’d introduce you to timers in JavaScript and how to use scope to make your life easier.
How we started
If you’ve been writing JavaScript for a while, you probably wrote your first timer calls like this (most likely, this guess for those of you who are new to JavaScript as well):
setTimeout("setBGColor()", 1000);
function setBGColor () {
document.body.style.backgroundColor = "#f00";
}
All fine and well, unless that if you start to validate your JavaScript with a tool such as JSLint, you’ll soon realize that using string as the first parameter in the call to setTimeout
is frowned upon (this of course goes for setInterval
as well). Instead, you’re told to use functions. The reason for this is that for a string parameter to work, you need to concatenate strings, just like the eval
statement, and it’s both a security hazard as well as a stability risk.
Using a function as the parameter
Following the advice we were given, we’re rewriting the above example with a function instead of a string. It would look a bit like this:
setTimeout(function () {
document.body.style.backgroundColor = "#f00";
}, 1000);
Instead of an anonymous function within the setTimeout
call, this could of course also be a function pointer:
setTimeout(setBGColor, 1000);
function setBGColor () {
document.body.style.backgroundColor = "#f00";
}
Note that this looks pretty much like our first example above with a string, except that the surrounding quotation marks and following parentheses are removed. I’ll show below why an anonymous function right there in the code is more useful than a function pointer.
Working with variables and references
All of the above code is fine and well, but what if we want to apply this style to whatever element that calls the function? And perhaps want to set the color at runtime too?
For the sake of making it easy, let’s call a function as soon as the window has loaded:
window.onload = function () {
setElmBGColor.call(document.body, "#ff0");
};
As you can see, we call the function in a certain element’s context (document.body
, in this case) using the call
method, and we also send in our desired color: “#ff0” (yellow, for those who don’t read hex π ).
setElmBGColor
function – using a string for evaluation
If we were to use the string version of setTimeout to create the setElmBGColor
function, it would have to look like this:
function setElmBGColor (bgColor) {
currentElm = this;
setTimeout("currentElm.style.backgroundColor = '" + bgColor + "'", 1000);
}
Notice that the currentElm
has to be global (the var
keyword preceding it has been omitted), because setTimout
is run in a global context, i.e. the window
object’s (remember, children, global variables are bad). Also, it becomes a matter of puzzling strings together, and, as stated above, could become a security concern. Not very nice.
setElmBGColor
function – using a function and scope
Instead, let’s look at using scope to help us out here:
function setElmBGColor (bgColor) {
var currentElm = this;
setTimeout(function () {
currentElm.style.backgroundColor = bgColor;
}, 1000);
}
setElmBGColor
function – using a function with scope and closure
We could of course get a little more fancy, using scope and a closure, to get rid of the currentElm
variable and solely use what context we’re in as the parameter for the function used in the setTimeout
call:
function setElmBGColor (bgColor) {
setTimeout(function (elm) {
return function () {
elm.style.backgroundColor = bgColor;
};
}(this), 1000);
}
A scalable and flexible solution
With all solutions mentioned here in this last part, it means that the setElmBGColor
function could be used for any element with any color. For instance, let change this:
setElmBGColor.call(document.body, "#ff0");
to this:
setElmBGColor.call(document.getElementById("container"), "#00f");
and it would work right out of the box. Quite nice, isn’t it? π
Conclusion
I hope I managed to inspire you a little to play around with JavaScript syntax, and explained why using functions instead of strings in timers is a lot more versatile and powerful.
Happy scripting! π
Yepp, thats timers like i’ve never done em before.
Good job man!
Henrik,
Thanks!
Thank you very much for this article. π
There’s one last thing I don’t really understand: In your example “Scope And Closure” you use scope in order to pass arguments to the anonymous function but also pass this as an argument. Why isn’t it possible to pass multiple arguments like this?
Chris,
Thanks!
You can send in any number of parameters you want to – this was just to simplify the object reference itself. But, just remember that the value of those parameters will be their value when the closure was created, i.e. when you caled
setElmBGColor
.There was a time I hunted the net for tutorials like this one. Nowadays I find this to be just basic stuff (off course π ). But man would I have loved to read this then. And for those who wonder: yes I’ve been guilty too. Until the day I heard the word ‘closure’, I used strings as parameters for timers. No worries, I’m cured now.
Robert, without any kidding, you’re really a fine teacher. Exact, to the point and still concerning alternatives. On top of that you pour it all into very readable texts that are quite enjoyable to read.
Ever thought of writing some JavaScript book? You would have at least one reader if the latter chapters would be a little more hardcore π
Stefan,
Stop it, you’re just making me blush!
But thank you! π
Not sure the book is going to happen. to be honest, I’ve had a few options/alternatives, but so far I’ve turned them – mostly because it takes a lot of time, effort and energy to write a book.
[…] JavaScript timers – using functions and scope […]
Hi Robert, one more translation of your great javascript articles into russian is here coders.ask-ru.net/question.aspx?qid2=290 . I really like to read your blog, it’s very useful!
coder,
Great, thank you!
[…] JavaScript Timers – Using Functions and Scope – Robert Nyman […]
[…] JavaScript timers – using functions and scope […]