var

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

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

试一试

var x = 1;

if (x === 1) {
  var x = 2;

  console.log(x);
  // Expected output: 2
}

console.log(x);
// Expected output: 2

语法

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...catchswitchfor 语句之一的头部,都不会为 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 new Error();
} 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® 2026 语言规范
# sec-variable-statement

浏览器兼容性

另见