让我们尝试转录ECMAScript® 2021 Language Specification的内容。
首先,根据JavaScript: Understanding the Weird Parts的说法,运行代码有两个阶段:创建阶段和执行阶段。从概念上讲,代码被处理两次(而不是执行)。
对于var a = 5;
语句,会发生以下情况:
- 创建阶段:为标识符a分配内存,并将未定义的值设置为该内存(称为提升)
- 执行阶段:将值5放入与标识符a相关联的内存中(而不是未定义)
现在,ECMAScript® 2021 Language Specification的14.3.2变量语句部分说:
一个
var 语句声明的变量是作用域限定在当前执行上下文的
VariableEnvironment 中的。当它们所属的
Environment Record 实例化时,var 变量被创建并在创建时初始化为
undefined。在任何
VariableEnvironment 的范围内,一个常见的
BindingIdentifier 可以出现在多个
VariableDeclaration 中,但这些声明只定义一个变量。由具有
Initializer 的
VariableDeclaration 定义的变量在执行 VariableDeclaration 时被分配其 Initializer 的
AssignmentExpression 的值,而不是在创建变量时分配。
让我们逐行分析。
在任何 VariableEnvironment 的范围内,一个常见的 BindingIdentifier 可以出现在多个 VariableDeclaration 中。
在这种情况下,BindingIdentifier 只是标识符。语句表示这些语法是正式允许的。
var a;
var a;
var a = 1;
var a = 2;
var a, a;
var a = 1, a = 2;
但是,这些声明只定义了一个变量。
直接说它是同一个变量,只分配了一个内存。
从概念上讲,如果在创建阶段具有标识符(在我们的情况下为a)的变量已经被创建,则其创建将被跳过(先前的语句已将内存分配并将未定义设置为其中)。
使用初始化程序定义的变量通过其初始化程序的赋值表达式在执行VariableDeclaration时被赋值,而不是在创建变量时被赋值。
这只是进一步强调了该语句的赋值(发生在执行阶段)和变量创建(发生在创建阶段)之间的差异。
var a = 5;
说明
现在让我们总结一下我们所知道的内容。
该语法是官方支持的。这意味着只会创建一个变量(一个内存位置来存储值)。
var a = 1;
var a = 2;
它与提升无关。提升仍然像往常一样发生。
console.log(a)
var a = 1;
var a = 2;
任务将在执行阶段逐行进行,更改位于同一内存位置的值。
console.log(a)
var a = 1;
console.log(a)
var a = 2;
console.log(a)