While working on a Web application recently, I came across a Javascript gotcha that I shouldn’t have faced in the first place.
As a matter of habit, I have made it a point to always declare variables inside a js function with the var keyword. I know many of us consider var optional for declaring a js variable. But how big a difference can this make to your code is best demonstrated by an example. Try clicking the “Click Me” button below, and analyze the output generated:
The above output is generated by the following js code:
{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }function outer() {
var i = 0;
j = 0;
for (var k = 0; k < 5; k++) {
inner();
i++;j++;
print(‘outer’, ‘Red’, i, j);
}
}
function inner() {
i = 0;
j = 0;
print(‘inner’, ‘Green’, i, j);
}
function print(scope, color, i, j) {
var div = document.createElement(‘div’);
div.style.color = color;
div.innerText = scope + ‘: i=’ + i + ‘, j=’ + j;
document.body.appendChild(div);
}{/syntaxhighlighter}
When you click the button, it invokes the outer method from the above code. This method declares 2 variables, i and j defaulting to zero, and then calls another method inner in a loop 5 times. After each call to inner, the values of i and j are incremented and outputted to the Html document.
The function inner itself assigns 0 to i and j simply.
Did you notice the difference in the values of i and j printed by the method outer (in Red)? Did you notice that i gets incrementing values from 1 to 5, but j always gets printed as 1?
Are you surprised? Well, you shouldn’t be, because according to the javascript language reference: “Javascript variables declared without the var keyword are global by default (even if the variable was declared inside a function)“.
Now, notice carefully the outer function above, i is declared with the var keyword, while j is declared without it. What this means is that i has local scope, whereas j is a global scoped-variable (because it was not declared using the var keyword).
When the method inner assigns 0 to i and j, it’s doing so for global variables i and j (because both are not using the var keyword). What this means is that it creates a global variable i with the value 0, and resets the global variable j created by outer to 0.
When the call returns to the outer method, and it prints i and j, it is referring to its local variable i, but global variable j (because there’s no j in the local scope for outer). So essentially, i gets incrementing values as a local variable, but the increment in the global variable j is reset by the inner method by assigning the global j to 0.
I think the output above should seem more logical now. What this implies is that, as a good programming practice, you should always declare your function scoped variables with the var keyword, unless you explicitly want them to be global (which I don’t think you should do, global variables are as hard to maintain as you can think of).
In my case, a deeply nested function call was changing such a variable which was not declared with the var keyword by a js method earlier in the call stack. The solution was simple, putting the var keyword in front of the declaration, but pinpointing the error code took much time (thousands of lines of js code with deeply nested calls).
So, using var should always be the thing you would like to consider while declaring variables inside javascript methods.
Recent Comments