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! πŸ™‚

 

Related reading

11 Comments

  • Henrik Pejer says:

    Yepp, thats timers like i’ve never done em before.

    Good job man!

  • Chris says:

    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?

  • Robert Nyman says:

    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.

  • Stefan Van Reeth says:

    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 πŸ™‚

  • Robert Nyman says:

    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 […]

  • coder says:

    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!

  • Robert Nyman says:

    coder,

    Great, thank you!

  • […] JavaScript Timers – Using Functions and Scope – Robert Nyman […]

  • […] JavaScript timers – using functions and scope […]

Leave a Reply to Robert Nyman Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.