Javascript重新声明的全局变量覆盖旧值
前几天我遇到了一个有趣的问题,我想知道是否有人能解释为什么会发生这种情况。以下是我正在做的事情(为了本例的目的,我稍微简化了示例):Javascript重新声明的全局变量覆盖旧值,javascript,global-variables,scope,Javascript,Global Variables,Scope,前几天我遇到了一个有趣的问题,我想知道是否有人能解释为什么会发生这种情况。以下是我正在做的事情(为了本例的目的,我稍微简化了示例): 我正在使用方括号符号创建一个全局范围的变量,并给它赋值 后来我声明了一个与我刚才创建的变量同名的变量。注意我没有赋值。由于这是同一变量的重新声明,因此不应按此处所述覆盖旧值: 问题是旧值实际上会被覆盖,在上面的示例中,警报显示“new”而不是“old”。为什么? 我想另一种表达我的问题的方式是,上述代码在语义上与下面的代码有何不同: //create glo
- 我正在使用方括号符号创建一个全局范围的变量,并给它赋值
- 后来我声明了一个与我刚才创建的变量同名的变量。注意我没有赋值。由于这是同一变量的重新声明,因此不应按此处所述覆盖旧值:
- 问题是旧值实际上会被覆盖,在上面的示例中,警报显示“new”而不是“old”。为什么?
//create global variable
var y = 'old';
//redeclaration of the same variable
var y;
if (!y) y = 'new';
alert(y); //shows Old
更新1:根据一些评论和答案,我重新表述了示例,以更好地反映我的原始问题
创建2个包含以下内容的javascript文件:
脚本1
脚本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中,页面实际上会提醒“新建”
更新2问题移到这里:当您使用
var y重新声明y
时
,现在它是未定义的,因此如果(!undefined)的计算结果为true,则
:
var
不会两次初始化变量,但会覆盖第一次未初始化的变量(因为它是一个新的、更局部的变量),window['y']
样式会这样做,将其添加到window对象中。以此为例:
//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
在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
}
因为也没有“块”范围。var
语句是提升的主题,这意味着当代码(就在实际运行之前)时,var
和函数
语句可用于其封闭范围
您的代码的计算结果如下:
第一个例子:
var y;
window['y'] = 'old';
if (!y) y = 'new';
alert(y);
第二个例子:
var y;
y = 'old';
if (!y) y = 'new';
alert(y);
挂起var
语句后,您可以看到代码的实际行为
另见:
- ?我刚刚测试了你的代码,它显示“old”,我测试了FF、Chrome、Safari(PC)和IE8
看看这里:如果这是真的,为什么第二段代码没有做同样的事情。第二段代码提醒“old”而不是“new”。我正在试图理解您所说的“var不会两次初始化变量,但会覆盖第一次未初始化的变量,正如window['y']样式所做的那样,并将其添加到window对象中。”这是否意味着window.y和y是不同的对象。我认为(可能是错误的)执行window.y或window['y']意味着创建一个名为y的全局变量。@Yousuf-这就是区别,
var y
与window.y
不同,它们是独立的变量,var y
是范围中两个变量中更局部的一个。@Yousuf-您可以直接访问它,像这样:window['y']='new';警报(y)
如果没有同名的局部变量,那么您将获得该局部变量。@优素福-有规范本身(取决于您运行的版本,取决于浏览器)…但我建议这样做,以便更实际地描述您在这里遇到的各种情况:最后一条语句并不完全正确,您可以使用let()
来获得块范围。您可以重新声明它,如果重新声明发生在同一范围级别<代码>var x=“foo”;var x;警报(x)@Nick,没错,但我将自己局限于所有主流浏览器实现的JavaScript子集@Matthew,你希望它显示什么?@Nick,let
是一个专有的Mozilla扩展,它只能在他们的JavaScript(TM)1.7引擎(SpiderMonkey,Rhino)@CMS上工作-我不会称之为“专有”(因为它在1.7规范中),Mozilla正式管理javascript…他们的引擎通常在其他引擎之前支持新的规范,或者出于同样的原因,这里就是这样。是的,如果第一个代码段在全局范围级别运行,window['y']
相当于var y
,因此它会提醒旧代码。JSFIDLE不是在全局范围内运行,而是在函数中运行。也许优素福的原始代码也在函数中。请参阅查看源代码:为什么在函数内部执行window['y']='old'与在全局范围内执行不同?优素福,window['y']
是相同的。不同的是vary
(在一个函数中,vary
创建一个新变量来隐藏全局变量,除非您使用window
),JSFIDLE让您“新建”是很奇怪的。我只是在本地创建了一个普通的HTML页面来测试这一点,当它直接从一个页面开始时,我仍然会得到“old”。@Matthew-对,但是var y是直接在脚本文件中声明的。它不在函数中。这就是我想表达的观点。既然它不在函数中,那么为什么它会覆盖旧值(因为它应该被视为一个重新声明,除非根据Nick的回答,这是两个不同的变量)你简化的部分一定是所有这些代码都在一个函数中的地方,给var y一个不同于window的范围。YY你的更新应该是一个新问题,特别是因为它是特定于浏览器的。我不认为提升是跨文件进行的,但我认为这是有意义的,因为它们在同一范围内执行。Afte
function b()
{
var z = 1;
if (true)
{
var z = 2;
}
alert(z); // 2
}
var y;
window['y'] = 'old';
if (!y) y = 'new';
alert(y);
var y;
y = 'old';
if (!y) y = 'new';
alert(y);