var

var 语句声明函数作用域或全局作用域变量,可以选择性地将每个变量初始化为一个值。

试一试

语法

js
var name1;
var name1 = value1;
var name1 = value1, name2 = value2;
var name1, name2 = value2;
var name1 = value1, name2, /* …, */ nameN = valueN;
nameN

要声明的变量的名称。每个变量必须是合法的 JavaScript 标识符解构绑定模式

valueN 可选

变量的初始值。它可以是任何合法的表达式。默认值为 undefined

描述

使用 var 声明的变量的作用域是以下最靠近 var 语句的带花括号的语法之一

或者,如果以上都不适用

  • 对于在模块模式下运行的代码,当前 模块
  • 对于在脚本模式下运行的代码,全局作用域。
js
function foo() {
  var x = 1;
  function bar() {
    var y = 2;
    console.log(x); // 1 (function `bar` closes over `x`)
    console.log(y); // 2 (`y` is in scope)
  }
  bar();
  console.log(x); // 1 (`x` is in scope)
  console.log(y); // ReferenceError, `y` is scoped to `bar`
}

foo();

重要的是,其他块构造,包括 块语句try...catchswitch一个 for 语句 的标题,不会为 var 创建作用域,并且在这样的块内使用 var 声明的变量可以在块外继续引用。

js
for (var a of [1, 2, 3]);
console.log(a); // 3

在脚本中,使用 var 声明的变量被添加为全局对象的不可配置属性。这意味着它的属性描述符不能更改,也不能使用 delete 删除。JavaScript 具有自动内存管理,因此能够对全局变量使用 delete 操作符毫无意义。

js
"use strict";
var x = 1;
Object.hasOwn(globalThis, "x"); // true
delete globalThis.x; // TypeError in strict mode. Fails silently otherwise.
delete x; // SyntaxError in strict mode. Fails silently otherwise.

在 NodeJS CommonJS 模块和原生 ECMAScript 模块 中,顶层变量声明的作用域为模块,不会作为属性添加到全局对象。

var 关键字后面的列表称为绑定列表,并用逗号分隔,其中逗号不是 逗号运算符= 符号不是 赋值运算符。后面变量的初始化器可以引用列表中前面的变量并获取初始化的值。

提升

var 声明无论在脚本中的哪个位置出现,都会在脚本中的任何代码执行之前被处理。在代码中的任何位置声明变量都等同于在顶部声明它。这也意味着变量可以在声明之前被使用。这种行为称为 提升,因为看起来变量声明被移动到了它所在的函数、静态初始化块或脚本源的顶部。

注意:var 声明只提升到当前脚本的顶部。如果您在一个 HTML 中有两个 <script> 元素,第一个脚本在第二个脚本被处理和执行之前无法访问第二个脚本声明的变量。

js
bla = 2;
var bla;

这被隐式理解为

js
var bla;
bla = 2;

因此,建议始终在它们作用域的顶部(全局代码的顶部和函数代码的顶部)声明变量,以便清楚地了解哪些变量的作用域是当前函数。

只有变量的声明被提升,而不是它的初始化。初始化只在到达赋值语句时发生。在此之前,变量仍然是 undefined(但已声明)

js
function doSomething() {
  console.log(bar); // undefined
  var bar = 111;
  console.log(bar); // 111
}

这被隐式理解为

js
function doSomething() {
  var bar;
  console.log(bar); // undefined
  bar = 111;
  console.log(bar); // 111
}

重新声明

使用 var 进行重复的变量声明不会触发错误,即使在严格模式下也不会,并且变量也不会丢失其值,除非声明具有初始化器。

js
var a = 1;
var a = 2;
console.log(a); // 2
var a;
console.log(a); // 2; not undefined

var 声明也可以与 function 声明在相同的作用域中。在这种情况下,var 声明的初始化器始终会覆盖函数的值,而与它们之间的相对位置无关。这是因为函数声明在任何初始化器被评估之前被提升,因此初始化器在后面出现并覆盖了该值。

js
var a = 1;
function a() {}
console.log(a); // 1

var 声明不能与 letconstclassimport 声明在相同的作用域中。

js
var a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared

由于 var 声明的作用域不是块,这也适用于以下情况

js
let a = 1;
{
  var a = 1; // SyntaxError: Identifier 'a' has already been declared
}

它不适用于以下情况,其中 letvar 的子作用域中,而不是相同的作用域

js
var a = 1;
{
  let a = 2;
}

函数体内的 var 声明可以与参数同名。

js
function foo(a) {
  var a = 1;
  console.log(a);
}

foo(2); // Logs 1

catch 块内的 var 声明可以与 catch 绑定标识符同名,但前提是 catch 绑定是简单的标识符,而不是解构模式。这是一种 已弃用的语法,您不应该依赖它。在这种情况下,声明被提升到 catch 块之外,但 catch 块内分配的任何值在外部不可见。

js
try {
  throw 1;
} catch (e) {
  var e = 2; // Works
}
console.log(e); // undefined

示例

声明和初始化两个变量

js
var a = 0,
  b = 0;

使用单个字符串值分配两个变量

js
var a = "A";
var b = a;

这等同于

js
var a, b = a = "A";

注意顺序

js
var x = y,
  y = "A";
console.log(x, y); // undefined A

在这里,xy 在任何代码执行之前被声明,但赋值在后面发生。在 x = y 被评估时,y 存在,因此不会抛出 ReferenceError,它的值为 undefined。因此,x 被分配了 undefined 值。然后,y 被分配了值 "A"

多个变量的初始化

注意 var x = y = 1 语法 - y 实际上并没有被声明为变量,因此 y = 1非限定标识符赋值,这在非严格模式下会创建一个全局变量。

js
var x = 0;
function f() {
  var x = y = 1; // Declares x locally; declares y globally.
}
f();

console.log(x, y); // 0 1

// In non-strict mode:
// x is the global one as expected;
// y is leaked outside of the function, though!

与上面相同的示例,但使用严格模式

js
"use strict";

var x = 0;
function f() {
  var x = y = 1; // ReferenceError: y is not defined
}
f();

console.log(x, y);

隐式全局和外部函数作用域

看起来像是隐式全局的变量可能是对外部函数作用域中变量的引用

js
var x = 0; // Declares x within file scope, then assigns it a value of 0.

console.log(typeof z); // "undefined", since z doesn't exist yet

function a() {
  var y = 2; // Declares y within scope of function a, then assigns it a value of 2.

  console.log(x, y); // 0 2

  function b() {
    x = 3; // Assigns 3 to existing file scoped x.
    y = 4; // Assigns 4 to existing outer y.
    z = 5; // Creates a new global variable z, and assigns it a value of 5.
    // (Throws a ReferenceError in strict mode.)
  }

  b(); // Creates z as a global variable.
  console.log(x, y, z); // 3 4 5
}

a(); // Also calls b.
console.log(x, z); // 3 5
console.log(typeof y); // "undefined", as y is local to function a

使用解构声明

每个 = 的左侧也可以是绑定模式。这允许一次创建多个变量。

js
const result = /(a+)(b+)(c+)/.exec("aaabcc");
var [, a, b, c] = result;
console.log(a, b, c); // "aaa" "b" "cc"

有关更多信息,请参阅 解构赋值

规范

规范
ECMAScript 语言规范
# sec-variable-statement

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参阅