【问题标题】:Javascript redeclared global variable overrides old valueJavascript 重新声明的全局变量覆盖旧值
【发布时间】:2010-04-14 13:10:55
【问题描述】:

前几天我遇到了一个有趣的问题,想知道是否有人可以解释为什么会发生这种情况。这是我正在做的事情(为了这个例子的目的,我稍微简化了这个例子):

  • 我正在使用方括号表示法创建一个全局范围的变量并为其分配一个值。
  • 稍后我声明了一个与我刚刚在上面创建的同名的 var。注意我没有赋值。由于这是对同一变量的重新声明,因此不应按照此处所述覆盖旧值:http://www.w3schools.com/js/js_variables.asp

    //create global variable with square bracket notation
    window['y'] = 'old';
    
    //redeclaration of the same variable
    var y;
    
    if (!y) y = 'new';
    
    alert(y); //shows New instead of Old
    
  • 问题是旧值实际上确实被覆盖了,并且在上面的例子中。警报显示“新”而不是“旧”。为什么?

我想另一种表达我的问题的方式是,上面的代码在语义方面与下面的代码有何不同:

//create global variable 
var y = 'old';

//redeclaration of the same variable
var y;

if (!y) y = 'new';

alert(y); //shows Old

更新 1 :根据一些 cmets 和答案,我将重新表述该示例以更能反映我原来的问题。

创建 2 个包含以下内容的 javascript 文件: 脚本1

//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 中打开此页面会提示“旧”,这是预期的行为。但是在 IE 8 中,页面实际上会提示“新”

更新 2 问题移至此处:Redeclared javascript global variable overrides old value in IE

【问题讨论】:

  • 你愚蠢的部分一定是所有这些代码都在一个函数中,给 var y 一个与 window.y 不同的范围
  • 您的更新应该是一个新问题,特别是因为它是特定于浏览器的。

标签: javascript global-variables scope


【解决方案1】:

当您用var y; 重新声明y 时,它现在是未定义的,所以if(!undefined) 的计算结果为真。

Add another alert in your example to see this:

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

//redeclaration of the same variable
var y;
alert(y); //undefined

if (!y) y = 'new';

alert(y); // new

var 不会两次初始化一个变量,但它会覆盖第一次未初始化的变量(因为它是一个新的、更局部的变量),window['y'] 样式会这样做,将其添加到窗口对象。以此为例:

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

//redeclaration of the same variable
var y;
alert(y); //undefined

alert(window.y); //old

if (!y) y = 'new';

alert(y); //shows New instead of Old
alert(window.y);​ //still old

【讨论】:

  • 如果这是真的,为什么第二个 sn-p 代码没有做同样的事情。代码的第二个 sn-p 提示“旧”而不是“新”
  • 我试图理解你所说的“var不会初始化一个变量两次,但它会覆盖一个第一次没有初始化的变量,这是window['y']样式所做的,添加它到窗口对象。”这是否意味着 window.y 和 y 是不同的对象。我认为(可能不正确)执行 window.y 或 window['y'] 意味着创建一个名为 y 的全局变量。
  • @Yousuf - 这就是区别,var ywindow.y 不同,它们是单独的变量,var y 在范围内是两者中更局部的。
  • @Yousuf - 你可以直接访问它,像这样:window['y'] = 'new'; alert(y); 如果没有更多同名的局部变量,那么你会得到取而代之的是那个局部变量。 ​
  • @Yousuf - 有规范本身(取决于您正在运行的版本,取决于浏览器)......但我建议这个更实用的描述各种情况像你'我碰到这里:digital-web.com/articles/scope_in_javascript
【解决方案2】:

您不能在 JS 的同一范围内“重新声明”类似的变量。

var x = "foo"
function a()
{
  alert(x); // undefined
  var x;
}

在函数a 中,变量x 是局部变量,因为它具有var x。不管是在使用之前还是之后。

同样:

function b()
{
  var z = 1;
  if (true)
  {
    var z = 2;
  }
  alert(z); // 2
}

因为也不存在“块”作用域之类的东西。

【讨论】:

  • 最后的说法并不完全正确,你可以使用let()来获取块作用域。
  • 如果重新声明发生在同一范围级别,您可以重新声明它。 var x = "foo"; var x; alert(x);
  • @Nick,没错,但我将自己限制在所有主流浏览器都实现的 JavaScript 子集。 @Matthew,你希望它显示什么?
  • @Nick,let 是一个专有的 Mozilla 扩展,它只适用于他们的 JavaScript (TM) 1.7 引擎(SpiderMonkey、Rhino)
  • @CMS - 我不会称它为“专有的”(因为它在 1.7 规范中),Mozilla 正式管理 javascript...授予他们的引擎通常在其他人之前支持新规范或出于同样的原因,就像这里的情况一样。
【解决方案3】:

?我刚刚测试了您的代码,它显示“旧”,并且我测试了 FF、Chrome、Safari (PC) 和 IE8。

看这里:http://jsbin.com/ifare/edit

【讨论】:

  • 是的,如果第一个 sn-p 在全局范围级别运行,window['y'] 等效于 var y,所以它确实会提醒 old。 jsfiddle 不是 在全局范围内运行,而是在函数中运行。可能优素福的原始代码也在一个函数中。查看源代码:fiddle.jshell.net/yaQYn/show/light
  • 为什么 window['y']='old' 在函数内部而不是在全局范围内执行不同?
  • 优素福,window['y'] 也一样。不同的是var y(在函数中,var y 创建一个隐藏全局的新变量,除非您使用window
  • jsFiddle 让你“新”很奇怪。我只是在本地创建了一个纯 HTML 页面来测试它,当它直接来自页面时,我仍然会变得“旧”。
  • @Matthew - 对,但是 var y 是直接在脚本文件中声明的。它不在函数内部。这就是我想要表达的观点。既然它不在函数内部,那么为什么它会覆盖旧值(因为它应该被视为重新声明,除非基于尼克的回答,它们是 2 个不同的变量)
【解决方案4】:

var 语句是 提升 的主题,这意味着当代码 enters in execution context(就在实际运行时之前)时,varfunction 语句可用于它的封闭范围。

您的代码实际上是这样评估的:

第一个例子:

var y;
window['y'] = 'old';

if (!y) y = 'new';

alert(y);

第二个例子:

var y;
y = 'old';

if (!y) y = 'new';

alert(y);

提升var 语句后,您可以看到代码的实际行为。

另见:

【讨论】:

  • 我认为提升不会发生在文件之间,但我认为这是有道理的,因为它们在同一范围内执行。
  • 做了一些测试,好像不是这样。
  • @Justin,对,我在用户编辑之前回答过,多个script 元素的问题似乎是IE 将重新设置为undefined 一个现有变量,当var语句用于单独的script 标记...
  • 啊,这更有意义。看来这是 IE 中的一个错误/“新功能”。
猜你喜欢
  • 2011-02-07
  • 2015-03-13
  • 2023-03-15
  • 1970-01-01
  • 2019-08-21
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多