【问题标题】:Initializing a JavaScript variable in the local scope在本地范围内初始化 JavaScript 变量
【发布时间】:2013-02-13 20:12:33
【问题描述】:

我正在研究 Javascript 中的变量作用域,并且遇到了变量声明和变量初始化之间的区别。通过与我认识的开发人员交谈,我的理解是,在变量声明之前编写 var 会将变量分配给本地范围,而在声明变量之前不编写 var 会将变量分配给全局范围。这是真的?

如果在声明变量之前写var确实将变量赋给了局部作用域,那么在初始化变量时是否需要写var以使其保持在局部作用域中?例如:

var someVariable;
// Do some things with JavaScript
someVariable = 'Some Value'

由于我在本地范围内用var 声明了someVariable,然后在没有使用var 的情况下初始化了someVariable,JavaScript 是否认为我只是在本地范围内初始化了一个变量,或者我声明了一个变量在本地范围内,然后声明在全局范围内初始化另一个变量?

稍后,当我想再次更改someVariable 的值时,是否需要在变量表达式之前编写 var,或者 JavaScript 会知道我正在更改已声明的局部变量的值?从技术上讲,JavaScript 如何知道我何时更改已声明的局部变量的值,以及何时声明和初始化全局变量?

【问题讨论】:

  • 我还要补充一点,我目前正在努力提高我对在谈论 JavaScript 时使用的正确术语的理解。因此,我不会因为我使用术语的方式被纠正而感到不安。

标签: javascript scope


【解决方案1】:
var something = "Initial value."

这意味着:“在本地范围内创建一个变量并给它一个初始值”。本地作用域是指您使用此语句的函数。

something = "New value."

这意味着:“在最近的范围内找到变量'某物',并为其分配一个新值”。 如果您使用第二个语句而不使用第一个语句,则该语句将在逐渐更大的范围内查找something 的任何定义(包含您的函数的函数,如果它存在,包含该函数的函数等,直到它到达全局范围)。如果它找到一些东西,它将分配给一个已经存在的变量。如果没有找到,它将创建一个具有该名称的全局变量。

如果您首先使用var,您只需确保此搜索始终在本地范围内停止。

【讨论】:

  • 这很有趣。所以这意味着如果一个人一直在全局范围内分配变量(不幸的是,在我开始理解范围之前,我有这样做的习惯),引擎有机会找到错误的变量来分配一个值?
  • 是的,在某些情况下,完全有可能通过在您的范围内本地定义相同的名称并在其中包含该函数来意外“捕获”某个函数试图引用的全局。
【解决方案2】:

我的理解是,在变量声明之前写 var 将变量分配给本地范围,而在声明变量之前不写 var 将变量分配给全局范围。这是真的吗?

不完全。

function foo() {
    var a = 1;
    function bar() {
        a = 2; // Still in the scope of foo, not a global
    }
}

由于我在本地范围内用var声明了someVariable,然后又不使用var初始化了someVariable,那么JavaScript是否认为我只是在本地范围内初始化了一个变量,或者我在本地范围内声明了一个变量,然后又声明了并在全局范围内初始化另一个变量?

在该示例中只有一个someVariable

以后想再改变someVariable的值时,是否需要在变量表达式前写var

var 为整个函数定义一个变量,无论它出现在函数的哪个位置。

【讨论】:

    【解决方案3】:

    这些都是一样的:

    var x;
    // ...
    x = 1;
    

    ...和...

    var x = 1;
    

    两者都在本地范围内定义一个变量并为其赋值。如果您想稍后在同一范围内更改变量的值,您可以简单地通过名称引用它:

    x = 2;
    

    但是,如果您在不同的范围内,除非变量首先在全局范围内声明,否则您将无法访问它(它“超出范围”)。尝试这样做将在全局范围内定义一个具有该名称的变量。

    function a(){
        var x = 1;
    }
    
    function b(){
        x = 2;  // 'x' in a is out of scope, doing this declares a new 'x' in global scope
    }
    
    a();
    b();
    

    当在声明的同一范围内引用变量时,您不需要在其前面加上var,但您可以:

    var x = 1;
    // ...
    var x = 2;
    

    ...没有必要这样做。虽然它将 2 分配给“x”,但它在逻辑上没有任何效果,因为 var 已经在本地范围内。但是,如果 x 已在全球范围内声明:

    var x = 1;
    
    function a(){
        var x = 2;
        console.log(x);
    }
    
    a();
    console.log(x);
    

    这将首先打印“2”,然后打印“1”。通过在函数中引用x 前面加上var,它将局部范围应用于变量。一旦函数完成,变量的原始范围就会恢复(或者重新范围丢失,如果你想这样看的话)。感谢@zzzzBov 指出这一点。

    希望这会有所帮助。

    【讨论】:

    • “这样做定义了一个同名的新变量”不完全。 var 仅将变量设置为该范围,重复使用 var 不会影响变量是否被替换。 assignment 是影响变量值是否变化的因素。为了说明这一点,var x = 1; var x; 的值仍然是 1,而不是 undefined
    • @zzzzBov 很好的观察,谢谢。我会更新我的答案。
    【解决方案4】:

    如果您使用var 定义一个变量,您可以在不反复使用var 关键字的情况下引用同一个变量。这些引用相同的变量:

    var someVariable;
    //...code...
    someVariable = 'rawr';
    

    如果您确实在每次更改变量时都使用了var 关键字,那么您将不会获得单独的变量。最新的声明只会覆盖最旧的声明。因此,除了初始化之外,使用 var 关键字没有任何意义。要更改someVariable 的值,您可以像上面的示例一样对变量名进行赋值。

    基本上,如果该范围内没有同名变量,则使用var 将创建一个新变量。

    现在以这段代码为例:

    var someVariable = 'initialized';
    
    function test1(){
      //this someVariable will be a new variable since we have the var keyword and its in a different scope
      var someVariable = 'test1';
      console.log(someVariable);
    }
    
    function test2(){
      //because there is no var keyword this refers to the someVariable in the parent scope
      someVariable = 'test2';
      console.log(someVariable);
    }
    
    console.log(someVariable); //initialized
    
    test1(); //test1
    console.log(someVariable); //initialized
    
    test2(); //test2
    console.log(someVariable); //test2
    

    通过此示例,您可以看到,根据您希望代码执行的操作,您可能会遇到问题。如果您希望 test2 表现得像 test1 并忘记使用 var 关键字,那么当您期望 someVariableinitialized 而不是 test2 时,您会感到困惑。

    但您也可以故意不使用 var 关键字,因为您希望 test2 更新父变量。所以正确使用var关键字很重要。

    初始化变量时不使用var 将在全局范围内创建变量。这不是好的做法。如果您想要全局范围内的变量,请手动将它们放在那里。即window.someVariable = 'initialize'; 这样任何看到您的代码的人都知道您故意将其设为全局变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 2013-04-05
      • 1970-01-01
      相关资源
      最近更新 更多