When running the following block of code, FF and Chrome output typeof(hiya) = string
while IE7/8 output typeof(hiya) = undefined
.
<html>
<body>
<script type="text/javascript">
window.hiya = 'hiya';
</script>
<script type="text/javascript">
if( false ) {
var hiya = 1;
}
document.write( "typeof(hiya) = "+ typeof(hiya) );
</script>
</body>
</html>
Each of the following makes the problem go away:
- Combining everything into a single
<script>
block. - Removing the
if
block. - Renaming
var hiya = 1
tovar hiya2 = 1
. - Renaming
var hiya = 1
towindow.hiya = 1
. - Renaming
var hiya = 1
tohiya = 1
.
What is happening? Is there a scoping bug in IE?
The core issue can be seen here http://jsfiddle.net/Raynos/UxrVQ/ I have yet to find out why IE overwrites window.hiya without checking.
[Edit]
From the specification. Page 38:
A possible explanation could be that in global scope IE differentiates between the
window
object and thevariable object
for global scope when declaring variables. Alternatively setting a property on thewindow
object directly might not set the same property on thevariable
object. If you can find a formal JScript specification or have the source of IE lying around then we can find out exactly what the quirk is.[/Edit]
Thanks to @TimDown & @JuanMendes pointing out that's an issue with whether writing a property to the window object is a variable declaration.
The Issue:
variable declaration gets moved to the top of the block. Even if the code is dead. In IE for some reason it will declare hiya as a local variable even though it classes with the property of the same name stored on window.
Explanation:
What's happening is that your declaring a variable called hiya. The var statement automatically gets removed to the top of the block. An if statement isn't a block, a function is. So event if the code never gets run in the block the variable still gets declared.
In firefox it'll recognise that window.hiya is a declaration of hiya.
In IE the declaration in the second script overwrites it
What it's actaully doing
In firefox:
In IE:
The solution is simply namespacing. You're using the same name in two places and accessing it in two different names. Either use different names or use closures to give local scope.
IE is dumb, it doesn't recognize that
window.varName
andvar varName
access the same variable in some cases.When a new script tag is encountered, it first initializes all the variables declared with var. It doesn't run the var statement (the part that would initialize it to "hiya"). It just initializes it to undefined. It won't do that if it was previously declared with var though.
If your code was in a single script tag, this error would not happen. Also, if the first declaration of hiya was done with var, this error also wouldn't happen.
Specifically, in your second script tag, IE first looks for var statements, it finds a var
var hiya = 1
; Then it says, hiya hasn't been initialized with a var statements previously (IE being dumb, other browsers recognize that window.hiya does the same thing) and initializes hiya, overwriting window.hiya before executing any code.Possible solutions:
Last note to clarify what JS parsers do to your code. When the JS parser sees your code, it transforms it into the following:
So if you put everything into one script tag, this is what the code would be (after the JS engine moved the var statements to the top), so you can see that there is no way the IE could mess it up, since your
window.hiya
assignment would be after the var that was moved to the top.What you encountered is due to:
var
being a statementSo what happens is that JavaScript will execute the
var
statement before before anything else, but it will not evaluate the assignment expression, thereforhiya
will default to the value ofundefined
.As Raynos already stated IE will execute each scripts on its own, therefore the behavior described above, will results in
hiya
being undefined.