This week I was chasing a javascript bug. At qualys we heavily rely on extjs, and we have a few thousands javascript files that have to live together. The bug ended up being in the following lines:
...
renderer: function(layer, text){
var tag = node = Ext.apply({
color: '#FCFCFC',
background: '#666666'
}, layer);
tag.text = tag.text || text;
if(node.disabled){
tag.style = "color: #CCC !important";
}
return tag;
},
...
Can you see what’s wrong?
…
The issue comes from the first line, an unconvenient mix of declarations and assignments:
var tag = node = Ext.apply({...})
The developer thought he was initializing 2 local vars called tag
and node
.
Let’s take something simple:
function test(){
var a = b = 2;
alert(a, b);
}
test();
alert(b);
In the first line, javascript starts by evaluating b = 2
. This is an assignment of 2
to the variable b
. Because b does not exist, javascript creates a new global variable b and attaches it to the current context, window
. (note that this would throw a ReferenceError exception if we were in strict mode).
A quick ref to ECMA-262 shows that assignments return the value that was just assigned. You can double check that in your console eval(b = 2);
returns 2
.
So now the compiler has evaluated the first expression and now reads var a = 2
since 2 was evaluated. This correctly creates a local variable a
containing the value 2 through a declaration, or more precisely a VariableStatement. note that eval(var b = 2);
returns undefined
.
Anyways… don’t mix up var a = [value]
with a = [value]
as they are completely different expressions that evaluate to different values and can create unexpected surprises…