运行以下代码块时,FF和Chrome输出typeof(hiya) = string
,而IE7 / 8输出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>
以下各项都会解决问题:
<script>
块。if
块。var hiya = 1
重命名为var hiya2 = 1
。var hiya = 1
重命名为window.hiya = 1
。var hiya = 1
重命名为hiya = 1
。发生了什么事? IE中是否存在范围错误?
答案 0 :(得分:26)
IE很愚蠢,在某些情况下,它无法识别window.varName
和var varName
访问同一个变量。
当遇到新的脚本标记时,它首先初始化用var声明的所有变量。它不运行var语句(将其初始化为“hiya”的部分)。它只是初始化为undefined。如果先前使用var声明它,它将不会这样做。
如果您的代码位于单个脚本标记中,则不会发生此错误。另外,如果hiya的第一个声明是用var完成的,那么这个错误也不会发生。
具体来说,在第二个脚本标记中,IE首先查找var语句,它会找到var var hiya = 1
;然后它说,hiya以前没有用var语句初始化(IE是愚蠢的,其他浏览器认识到window.hiya做同样的事情)并初始化hiya,在执行任何代码之前覆盖window.hiya。
可能的解决方案:
最后请注意澄清JS解析器对您的代码所做的事情。当JS解析器看到您的代码时,它会将其转换为以下内容:
<html>
<body>
<script type="text/javascript">
window.hiya = 'hiya';
</script>
<script type="text/javascript">
// IE is dumb, it doesn't recognize that hiya is already
// defined as window.hiya, so it's initialized to undefined here
var hiya;
if( false ) {
hiya = 1;
}
document.write( "typeof(hiya) = "+ typeof(hiya) );
</script>
</body>
</html>
因此,如果将所有内容放入一个脚本标记中,这就是代码所在的内容(在JS引擎将var语句移到顶部之后),因此您可以看到IE无法将其搞砸,因为你的window.hiya
作业将在移动到顶部的var之后。
<html>
<body>
<script type="text/javascript">
var hiya;
window.hiya = 'hiya';
if( false ) {
hiya = 1;
}
document.write( "typeof(hiya) = "+ typeof(hiya) );
</script>
</body>
</html>
答案 1 :(得分:10)
核心问题可以在这里看到http://jsfiddle.net/Raynos/UxrVQ/我还没有找到为什么IE覆盖window.hiya而不检查。
<强> [编辑] 强>
从规范。第38页:
对于每个VariableDeclaration或 代码中的VariableDeclarationNoIn, 创建变量的属性 名称为标识符的对象 VariableDeclaration或 VariableDeclarationNoIn,其值 是未定义的,其属性是 由代码类型决定。如果 已经有了财产 名称为a的变量对象 声明变量,值的 属性及其属性不是 改变。
可能的解释是,在全局范围内,IE在声明变量时区分全局范围的window
对象和variable object
。或者,直接在window
对象上设置属性可能不会在variable
对象上设置相同的属性。如果您可以找到正式的JScript规范或者有IE的来源,那么我们就可以确切地知道怪癖是什么。
<强> [/编辑] 强>
感谢@TimDown&amp; @JuanMendes指出,向window对象写一个属性是一个变量声明是一个问题。
问题:
变量声明被移动到块的顶部。即使代码已经死了。在IE中出于某种原因,它会将hiya声明为局部变量,即使它使用存储在窗口中的同名属性进行分类。
<强>解释强>
发生的事情是你声明一个名为hiya的变量。 var语句自动被删除到块的顶部。 if语句不是块,函数是。因此,如果代码永远不会在块中运行,则变量仍会被声明。
在Firefox中,它会识别出window.hiya是hiya的声明。
在IE中,第二个脚本中的声明会覆盖它
它正在做什么
在firefox中:
// script block 1
var hiya; // window.hiya counts as a declaration
window.hiya = "hiya"; // set
// script block 2
if (false) hiya = 1;
document.write(...)
在IE中:
// script block 1
window.hiya = "hiya";
// script block 2
var hiya; // redeclared here because window.hiya "isn't" a declaration
if (false) hiya = 1;
document.write(...)
解决方案只是命名空间。您在两个地方使用相同的名称,并以两个不同的名称访问它。使用不同的名称或使用闭包来给出局部范围。
答案 2 :(得分:3)
您遇到的原因是:
var
是一份声明所以会发生的事情是JavaScript会先于var
语句执行,但它不会评估赋值表达式,因此hiya
将默认为undefined
的值。
由于Raynos已经声明IE将自己执行每个脚本,因此上述行为将导致hiya
未定义。