Get to know MDN better
要声明的变量的名称。必须是有效的 JavaScript 标识符或解构绑定模式。
valueN 可选变量的初始值。可以是任何合法的表达式。默认值为 undefined。
用 var 声明的变量的作用域是最靠近并包含 var 语句的以下花括号闭合语法结构的一个:
如果不是以上这些情况则是:
重要的是,其他块级结构,包括块语句、try...catch、switch 以及其中一个 for 语句的头部,对于 var 并不创建作用域,而在这样的块内部使用 var 声明的变量仍然可以在块外部被引用。
在脚本中,使用 var 声明的变量将被添加为全局对象的不可配置属性。这意味着它的属性描述符无法被修改,也无法使用 delete 删除。JavaScript 具有自动内存管理机制,因此在全局变量上使用 delete 运算符是没有意义的。
在 NodeJS CommonJS 模块以及原生 ECMAScript 模块中,顶层变量声明的作用域仅限于模块中,而不会作为属性被添加到全局对象中。
var 关键字后面的列表被称为绑定列表,用逗号分隔,其中逗号不是逗号运算符,= 号也不是赋值运算符。后续变量的初始化可以引用前面的变量,并获得初始化的值。
var 声明,无论它们出现在脚本中的什么位置,都会在执行脚本中的任何代码之前进行处理。在代码中的任何位置声明变量都相当于在顶部声明它。这也意味着变量可以在其声明之前被使用。这种行为被称为提升,因为变量声明似乎被移动到发生该行为的函数、静态初始化块或脚本源代码的顶部。
备注:var 声明仅提升到当前脚本的顶部。如果在一个 HTML 文件中有两个 <script> 元素,则第一个脚本无法访问第二个脚本声明的变量,直到第二个脚本已被处理和执行。
这可以隐式理解为:
因此,建议始终在作用域的顶部(全局代码的顶部和函数代码的顶部)声明变量,以便清楚地知道哪些变量是作用域限定在当前函数内部的。
只有变量的声明被提升,而变量的初始化则不会被提升。直到赋值语句被执行,变量才会被初始化。在此之前,变量的值是 undefined(但已声明):
这可以隐式理解为:
即使是在严格模式下,使用 var 重复声明变量不会触发错误,变量的值也不会丢失,除非新的声明有初始化器。
var 可以与 function 在同一作用域中声明同名变量。在这种情况下,var 声明的初始化器总是会覆盖函数的值,而无论它们的相对位置如何。这是因为函数声明会提升到作用域的顶部,而初始化器会在其后才被求值,因此会覆盖函数的值。
var 不能与 let、const、class 或 import 在同一作用域中声明同名变量。
因为 var 声明作用域不限于块,所以这也适用于以下情况:
它不适用于以下情况,其中 let 位于 var 的子作用域中,而不是同一作用域:
函数体内的 var 声明可以与函数参数同名。
catch 块内的 var 声明可以与 catch 绑定的标识符同名,但只有当 catch 绑定的是一个简单标识符,而不是解构模式时才可以。这是一种已弃用的语法,你不应该依赖它。在这种情况下,声明会被提升到 catch 块外部,但在 catch 块内的任何赋值都不会在外部可见。
等效于:
留意其中的顺序:
在这里,x 和 y 在代码执行之前已经声明了,而赋值发生在其之后。在执行 x = y 时,y 已经存在,因此不会抛出 ReferenceError,并且它的值是 undefined。所以,x 被赋值为 undefined。然后,y 被赋值为 "A"。
请注意 var x = y = 1 语法——y 实际上并没有声明为变量,因此 y = 1 是非限定标识符赋值,在非严格模式下会创建全局变量。
在严格模式下运行相同的示例:
看起来像是隐式全局作用域的变量也有可能是其外部函数变量的引用:
每个 = 的左侧也可以是一个绑定模式。这允许一次创建多个变量。
有关更多信息,请参阅解构。
| ECMAScript® 2027 Language Specification # sec-variable-statement |
启用 JavaScript 以查看此浏览器兼容性表。