Be careful with JavaScript variable declarations

Monday, 30 July 2007

Make sure you declare all your JavaScript variables exactly once. Otherwise it’s easy to introduce bugs that are hard to diagnose, especially if you’re used to programming in a C-like language such as Java, C++ or C#.

Local variables in JavaScript are scoped to the function they are in, not to their containing block. This is different to C++, Java and similar languages. One of the consequences of this is that a var statement by itself generally does nothing at all, unlike in C++, Java, etc. Here’s a contrived example.

for (var i = 0; i < 5; ++i) {
	var t;
	// If i is even then set t to "even"
	if (i % 2 == 0) {
		t = "even ";
	}
	// If t is not set then i must be odd
	if (!t) {
		t = "odd ";
	}
	document.write(t);
}

After one iteration, t contains the value “even “. In the second iteration, a Java or C++ programmer might expect the var t to initialise the variable t again, so t will subsequently end up with the value “odd “. But actually the var t has no effect and t always has the value “even “. The program above writes “even even even even even ” to the document.

The fix is simple. Instead of an ineffectual var t, use var t = null to explicitly set the value of t. In fact, you could follow Douglas Crockford’s JavaScript coding conventions, which recommend:

All variables should be declared before used. JavaScript does not require this, but doing so makes the program easier to read and makes it easier to detect undeclared variables that may become implied globals.

The var statements should be the first statements in the function body.

JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.

Following this recommendation, you’d write the following code, which produces “even odd even odd even ” in proper accordance with the laws of parity.

var t;
var i;
for (i = 0; i < 5; ++i) {
	t = null;
	// If i is even then set t to "even"
	if (i % 2 == 0) {
		t = "even ";
	}
	// If t is not set then i must be odd
	if (!t) {
		t = "odd ";
	}
	document.write(t);
}

Tags:

3 comments

You can leave a comment, or trackback from your own site.

  1. Regardless of the guarantees that modern C, C++, and Java give about clearing memory when declaring a variable, it is always good practice to set a variable unconditionally before reading from it. This is as much for program readability as it is for avoiding problems like the case you bring up.

  2. Well, of course this is mandatory in C and C++ since they make no such guarantees. I agree with you in the case of Java because it silently initialises variables to a plausible value (e.g. 0 for numeric variables) which might therefore be used by accident if you forget to initialise it properly.

    But in dynamically-typed languages like JavaScript it makes less sense since variables are initialised to a special value (undefined) — if it gets used by accident then the error will be immediately obvious.

    Having said that, it doesn’t hurt to put “= 0” or “= ""“, does it?

Leave a comment