在IE浏览器中,重新声明Javascript全局变量会覆盖旧值

10

(在评论之后创建一个单独的问题: Javascript 重新声明全局变量会覆盖旧值)

我使用方括号表示法创建一个全局作用域的变量,并在外部js文件中给它分配一个值。

在另一个js文件中,我声明了一个与上面创建的变量同名的变量。请注意,我没有分配一个值。由于这是对同一变量的重新声明,旧值不应被覆盖,如此处所述:http://www.w3schools.com/js/js_variables.asp

创建以下内容的2个JavaScript文件: Script1

//create global variable with square bracket notation
window['y'] = 'old';

脚本2

//redeclaration of the same variable
var y;

if (!y) y = 'new';

alert(y); //shows New instead of Old in IE

在你的HTML文件中包含这两个文件。

<html>
 <head></head>
 <body>

  <script type="text/javascript" src="my.js"></script>
  <script type="text/javascript" src="my2.js"></script>

 </body>
</html>

在 Firefox 和 Chrome 中打开此页面会弹出“old”,这是预期行为。然而在 IE 8 中,页面实际上会弹出“new”。

对于为什么 IE 会发生这种情况,有什么想法吗?


如果您将所有代码嵌入HTML文件中会发生什么?对我来说,在Firefox 3.5.8、Chrome 5.0.342.7和Konqueror 4.3.5中都会得到相同的结果(旧版)。其他浏览器的结果也会很有用。 - Matthew Flaschen
如果您将所有代码放在一个文件中,那么变量提升会发生,问题可能就不会出现。 - Justin Johnson
如果您将所有代码放在一个单独的位置,警报将在所有浏览器上显示“旧版”。 - Yousuf Haider
3个回答

10

简单的测试案例:

<script>
    window.foo= 1;
</script>
<script>
    var foo;
    alert(foo);
</script>

没错,这绝对是IE的JScript引擎中的一个bug。

为什么会发生这种情况?IE为什么会做任何疯狂的事情呢?发出一声不满的嘟囔,继续前进,尽量避免这样做...


2
如果你已经缩小了问题范围,只剩下“你的问题”和“IE的问题”,那么每次都选择IE。 - bobince

4
如果你想让变量 y 成为全局变量,你可以在第二个文件中省略 var y 这行代码。这么做的原因是,既然你希望 y 是全局变量,那就把它当作已经声明过的全局变量来处理。JavaScript 在没有使用 var 前缀声明变量时自动将其变成全局变量,这种副作用在这种情况下对你有利。在 IE8 中测试,这样做完全可行。
编辑:至于为什么会出现这种情况,我认为这只是 IE 处理跨文件全局变量和声明提升的 Bug。不过,你应该只在一个地方声明任何变量,尤其是全局变量。遵循这个经验法则可以避免你的问题。

1
谢谢你的建议。很有道理。不过,了解为什么在IE中无法正确运行仍然很有趣。 - Yousuf Haider
1
令人惊讶的是,IE 浏览器可能存在 JavaScript 实现方面的错误。 - Justin Johnson
是的,理想情况下我们只需要在一个地方声明全局变量。我的使用情况是有多个JS文件,每个文件都使用这种模式声明一个命名空间类:Script1: if (!a) a = {}; a.b = function() {....};Script2: if (!a) a = {}; a.c = function() {....};现在这样做很好,直到第一个脚本使用window.a或window['a']来声明a,然后IE就会崩溃。由于多个页面可以选择包含哪些文件,它们中的每一个都必须检查a是否存在。 - Yousuf Haider
我早就猜到了。这与“dojo.declare”类似。你可能想看看他们是如何做的,或者甚至只是使用dojo:http://api.dojotoolkit.org/jsdoc/1.3/dojo.declare - Justin Johnson
有趣的是,这个 bug 出现是因为我有自己的自定义 dojo widget 以及使用相同命名空间前缀的类。例如:a.myDojoWidget(dojo widget)后跟 a.myClass(简单 js 类)问题在于 dojo.declare 以这种方式声明类: window['a'] = {},然后 a['myDojoWidget'] = ..根据您的建议,我通过不使用 var a 来避免了这个问题。 - Yousuf Haider

1

这是在IE中发生的,因为重新声明的行将y设置为未定义。然后测试是否未设置y的行通过,并且y更改为“new”。

将第二个脚本更改为:

//redeclaration of the same variable
var y;

alert(y); // is undefined in IE

if (!y) y = 'new';

alert(y); //shows New instead of Old in IE

1
我明白。但如果您将这两个文件的内容合并到一个单一的位置,则y将不再是未定义的,重声明也不会将y设置为未定义。因此,警报将显示“旧”。 - Yousuf Haider
在IE中,所有声明都会在代码的其他部分之前执行。在第二个include中,如果您在第一行中添加alert(window['y']),您会发现该值为undefined。如果您注释掉重新声明的行,您将看到预期的“old”出现。 - Jonathan
实际上,这在所有浏览器中都会发生,被称为提升;然而,在这种情况下,IE似乎做错了,导致了覆盖。 - Justin Johnson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接