为什么局部变量会覆盖全局变量?

27

非常抱歉问这个问题,但这个问题真的让我一整天都被困扰。

以下的代码会像它应该的那样弹出一个警告框,显示10:

var globalId='10';  
function check(){  
    alert(globalId);  
}  
check();

但是下面的代码会弹出一个未定义的警告框:

var globalId='10';  
function check(){  
    alert(globalId); 
    var globalId; 
}  
check();
我知道如果我在函数内声明一个变量,它是局部变量。但如果我已将它声明为全局变量,为什么我的警报会显示“未定义”?
这是一个简单的例子,但在我的原始代码中,我在函数开头之间做了很多事情,然后很长一段时间我检查是否定义了globalId,否则定义它:if(!globalId){var globalId;} 这意味着我的警报位于函数顶部生成了未定义,就好像JavaScript首先执行整个函数,只是为了看看是否可能声明任何变量,如果是,声明它们,因此我的警报指向一个“未声明”的变量。
有人能解释一下为什么会发生这种情况吗?如果JavaScript "预先声明"所有变量在执行函数之前,甚至条件不符合的变量也声明了吗?

本地变量始终优先于全局变量,这在C和大多数其他语言中都是如此。在C++中,您可以通过::选择全局变量。无论如何,将全局变量和本地变量命名类似是一种不好的做法。 - phuclv
6个回答

24
在JavaScript中,你应该知道有一种叫做变量提升的东西。
这基本上意味着,当你声明任何局部变量时,变量声明会自动移到作用域的顶部。
例如:
var globalId='10';
function check(){
alert(globalId); var globalId; }
check(); 

更改为 -

var globalId='10';
function check(){
var globalId;
alert(globalId);}
check(); 

由于 globalID 仍未被赋值,因此在您的输出中返回 undefined。具有相同名称的局部变量始终优先于全局变量。


首先,非常感谢在这里迅速给我关于作用域的答案的你和其他人。我不知道所有变量在执行之前都会被移动到顶部。但是这里有一个缺陷,就是如果我在函数内声明变量var globalId="ABC123",它仍然会弹出未定义。声明不能被移动到顶部,如果可以的话,我的警报不应该是“ABC123”而不是未定义吗?在我看来,Javascript移动了全局id将被声明的概念,因此在代码中稍后进行访问之前无法访问它...? - Per Spjuth
7
@per Spjuth - 只有声明被移至顶部,而不是赋值。因此,如果您在警报之前没有赋值操作,则仍将得到未定义的结果。 - Sachin Shanbhag

17

是的,函数内声明的所有变量都是局部变量,并且在整个函数代码中存在;它们将优先于同名的全局变量使用。

来自https://developer.mozilla.org/en/JavaScript/Guide/Values,_Variables,_and_Literals#Variable_Scope

JavaScript没有块级作用域;相反,它将局部变量限定在其所在代码中。[...] JavaScript中另一个不寻常的变量特性是,您可以引用稍后声明的变量,而不会出现异常。这个概念称为提升;JavaScript中的变量在某种程度上被“提升”或移到函数或语句的顶部。


13

在您的第二段代码中,局部变量掩盖了全局变量。

var globalId='10';

function check() {
    // Your are defining a local variable in this function
    // so, the global one is not visible.
    alert(globalId);
    var globalId;
}

check(); 


即使在函数定义的末尾使用了var声明变量,也不会改变全局变量被函数掩盖的事实整个函数中都会生效。

因此,在函数执行期间,globalId变量将引用本地变量而不是全局变量。

然而,在函数外部,全局变量仍然存在,只是由于var语句无法从函数内部看到它而已。


4
如前所述,遵循JavaScript作用域规则,局部变量在整个函数中覆盖全局变量。但是可以访问全局变量,请尝试以下操作。
var globalId='10';

function check() {
    // Your are defining a local variable in this function
    // so, the global one is not visible.
    alert('Local : ' + globalId + ', Global : ' + window.globalId);
    var globalId;
}

check(); 

0

你在函数作用域内声明了一个新变量globalId,所以它是未定义的,这是正确的。不,它不会破坏你的全局变量,你可以在check();调用后添加alert(globalId);来检查。


0
就好像Javascript首先执行整个函数,只是为了看看是否有任何变量“可能”被声明。
这就是答案,或多或少。JavaScript解释器在每个作用域中查找变量声明,然后将它们“移动”到作用域的顶部。

Javascript并不会_执行_整个函数,它只是_解析_函数。在实际执行函数之前,声明会被提前移动到顶部。 - Martijn

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