声明与初始化变量?

use*_*128 9 javascript variable-initialization variable-declaration

我很想知道声明变量和初始化变量之间的区别.例如

var example; // this is declaring

var example = "hi" // initializing? Or just "adding a value"?
Run Code Online (Sandbox Code Playgroud)

我不认为我就在那里,但每个人的定义究竟是什么?或者他们基本上是同一个意思?

jma*_*777 12

编辑:@ThisClark在评论中说了些什么,我去证明他是错的,在阅读规范后我学到了一些东西:

除了规范之外,这里有一些信息:

一个var声明宣称,被限定在运行中的执行上下文的VariableEnvironment变量.Var变量在实例化包含词法环境undefined时创建,并在创建时初始化.[...]在执行VariableDeclaration时,由VariableDeclaration和Initializer定义的变量被赋予其Initializer的AssignmentExpression的值,而不是在创建变量时.

根据我对此的解读,以下几点描述了您在问题中询问的行为(以及术语的"正确用法"):

  • 变量声明(例如,var foo)导致该变量被创建只要"词法环境"被实例化.例如,如果该变量是在函数体中定义的,那么该函数就是"词法环境",因此变量创建与函数本身的实例化一致.

  • 显然,变量声明可以或可以不与一个创建初始化(即,右手表达解析为变量的初始值).这是"初始值"一词的非规范用法,但是......让我们再深入研究一下:

  • 从技术上讲,根据此处的规范说明,所有变量都使用以下值初始化undefined:

    变量已创建[...]并初始化为未定义

    在那里强调"技术上",因为如果还提供初始化器,这在很大程度上是学术性的.

  • 基于我们已经涵盖的内容,应该理解语句var foo;可以存在于函数体内的任何位置,并且在同一函数内的任何其他位置移动它将不会影响函数本身的运行时语义(无论是否/任何实际的任务或其他参考foo发生的地方).如果这仍然令人困惑,请重新阅读之前的观点.

  • 最后一点行为是最直观的部分,这是初始化程序分配.这个赋值发生在实际执行该行代码时(同样,在技术上创建变量的时间点不同).

所以,快速回顾一下:

  • 所有变量声明(使用var)总是undefined在其词法环境初始化时初始化.
  • 这可能初始化不计为转让,在技术意义上(哈,@ThisClark,你错的!).:)
  • 分配是很容易的部分,因为它们的行为方式(以及在您预期的时间点).

希望有所帮助(而且我并没有非常误解规范!).

  • 看?规格并不“那么”难以理解。;-) (2认同)

Mar*_*hes 11

@jmar777 的答案绝对是规范的最佳解释和细分。然而,我发现对于我们动手的学习者来说,一些说明性的代码是有帮助的!;)


基本理念

  • “声明”使变量在给定范围内可用。
  • “赋值”在代码中的那个位置给一个变量一个特定的值。如果您尝试为从未在该作用域或父作用域中声明过的变量赋值,则该变量将在全局作用域中隐式声明(等同于 Typing window.varName = value)。
  • “初始化”是发生在“幕后”或“幕后”的事情,可以这么说。在运行时,所有的声明变量初始化一个开始分配undefined(即使他们立即会被分配在第一行代码不同的值)。

因此,初始化对我们来说不是一个重要的术语。我们声明并赋值,Javascript 引擎初始化。

因此,要直接回答问题中的示例:

  • var example;声明一个变量,该变量undefined在初始化期间被赋值为。
  • var example = "hi"声明一个变量,它undefined最初也被分配了一个值,但是当在执行过程中实际到达那行代码时,它被重新分配给字符串“hi”。


说明性代码

function testVariableDeclaration() {

    // This behaves 'as expected'....

    console.log(test2, 'no value assigned yet'); // --> undefined 'no value assigned yet'

    // ....but shouldn't our actual expectation instead be that it'll throw an error since
    // it doesn't exist yet? See the final console.log() below!


    // As we all know....

    test1 = 'global var'; // ....a variable assignment WITHOUT declaration in the current
                          // scope creates a global. (It's IMPLICITLY declared.)

    // But a little counter-intuitively....

    test2 = 'not global'; // Although this variable also appears to be assigned without
                          // declaration like 'test1', the declaration for 'test2' that
                          // appears *later* in the code gets hoisted so that it's already
                          // been declared in-scope prior to this assignment.

    console.log( test1, window.test1 === test1 ); // --> 'global var' TRUE
    console.log( test2, window.test2 === test2 ); // --> 'not global' FALSE

    var test2; // As shown by the above console.log() outputs, this variable is scoped.

    console.log( test3 ); // Throws a ReferenceError since 'test3' is not declared
                          // anywhere, as opposed to the first console.log() for 'test2'.
}
Run Code Online (Sandbox Code Playgroud)


“范围”对声明/分配的影响

使声明和赋值之间的区别更加清晰的是,声明一个变量总是会在当前作用域 ( myVarscopeB )内创建一个新变量,即使父作用域 ( myVarscopeA ) 中已经存在同名变量。然后我们可以在当前范围内的任何点为scopeB分配一个新值,而无需重新声明它。(该转让不影响价值scopeA)。一旦结束scopeB到达,scopeB将不再可用于分配。myVarmyVarmyVar

另一方面,如果我们为给定范围内的变量赋值而不在该范围内声明它,它将被分配给“范围链”中的下一个最高声明(或者全局将被隐式如果没有找到更高的声明,则声明)。

因此,一个变量只需要在每个作用域声明一次,每个声明覆盖在父作用域中所做的任何声明(即它创建一个不同的变量)。但是,如果它是该范围内唯一的,则必须在范围内声明它。赋值可以根据需要进行多次,但只影响最“密切声明”的变量(因为没有更好的术语)。