Javascript 为什么IE使用nuke window.ABC变量?

Javascript 为什么IE使用nuke window.ABC变量?,javascript,internet-explorer,scope,browser-bugs,Javascript,Internet Explorer,Scope,Browser Bugs,当运行以下代码块时,FF和Chrome输出typeof(hiya)=string,而IE7/8输出typeof(hiya)=未定义 <html> <body> <script type="text/javascript"> window.hiya = 'hiya'; </script> <script type="text/javascript">

当运行以下代码块时,FF和Chrome输出
typeof(hiya)=string
,而IE7/8输出
typeof(hiya)=未定义

<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>

window.hiya='hiya';
if(false){
var hiya=1;
}
文件。书写(“typeof(hiya)=“+typeof(hiya));
以下每一项都会使问题消失:

  • 将所有内容合并到一个
    块中
  • 删除
    if
  • var hiya2=1
    重命名为
    var hiya2=1
  • var hiya=1
    重命名为
    window.hiya=1
  • var hiya=1
    重命名为
    hiya=1

发生了什么?IE中是否存在范围缺陷?

核心问题可以在这里看到,我还没有找到IE未经检查就覆盖window.hiya的原因

[编辑]

从规范中删除。第38页:

对于每个变量声明或 代码中的VariableDeclarationNoIn, 创建变量的属性 对象,其名称是中的标识符 变量声明或 VariableDeclarationNoIn,其值为 未定义,且其属性为 由代码类型决定。如果 已存在的属性 名为 声明的变量的值 属性及其属性不可用 变了

一种可能的解释是,在全局范围内,IE在声明变量时区分了全局范围的
窗口
对象和
变量对象
。或者,直接在
窗口
对象上设置属性可能不会在
变量
对象上设置相同的属性。如果你能找到一个正式的JScript规范,或者有IE的来源,那么我们就可以确切地找出其中的怪癖

[/Edit]

感谢@TimDown&@JuanMendes指出,将属性写入窗口对象是否是变量声明是一个问题

问题:

变量声明被移动到块的顶部。即使代码死了。在IE中,由于某种原因,它会将hiya声明为局部变量,即使它使用存储在window上的同名属性初始化

说明:

现在发生的是,您声明了一个名为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(...)

解决方案只是名称空间。您在两个地方使用相同的名称,并使用两个不同的名称访问它。使用不同的名称或使用闭包来提供本地范围。

您遇到的问题是由于:

  • var
    是一个语句
  • JS中没有块作用域
  • 语句在代码运行之前执行
  • 因此,JavaScript会先执行
    var
    语句,然后再执行其他语句,但它不会计算赋值表达式,因此
    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>
    

    正如Raynos已经声明的那样,IE将自己执行每个脚本,因此上述行为将导致
    hiya
    未定义。

    IE是哑的,在某些情况下,它无法识别
    window.varName
    var varName
    访问相同的变量

    当遇到新的脚本标记时,它首先初始化使用var声明的所有变量。它不运行var语句(将其初始化为“hiya”的部分)。它只是将其初始化为未定义。但是,如果它以前是用var声明的,它就不会这样做

    如果代码位于单个脚本标记中,则不会发生此错误。此外,如果hiya的第一次声明是使用var完成的,那么也不会发生此错误

    具体来说,在第二个脚本标记中,即首先查找var语句,它会找到var
    var hiya=1
    ;然后它说,hiya以前没有用var语句初始化过(也就是说,如果是哑的,其他浏览器会识别window.hiya做同样的事情),并初始化hiya,在执行任何代码之前覆盖window.hiya

    可能的解决办法:

    • 将代码保持在同一个脚本标记内
    • 不要使用window.hiYa初始化变量
    • 如果您不能控制其中一个脚本,请确保首先使用var的脚本
    最后一点说明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>
    

    一开始就不要写这么棘手的东西怎么样哈。我遇到的现实问题要复杂得多,如果没有加载另一个库,则会有一个条件来定义某些内容。这是我可以解决的问题,但我真的很想知道为什么会发生这种情况。@delnan:Snarky,嗯?我认为很明显,这不是真正的代码,这只是一个减少,显示了问题。就像所有操作人员在发布问题之前应该做的一样,我在Ext.ns中遇到了同样的问题,它使用window从字符串创建名称空间。。在其他地方,在googleclosure生成的一些模板代码中,它还试图创建到相同的名称空间(cci.templates)中,并覆盖了原始的cci名称空间对象,因为它在全局范围中使用了一个var来生成名称空间对象。起初我很困惑,因为它会测试
    如果(!wi