var

var 语句声明函数范围或全局范围的变量,可以选择将每个变量初始化为一个值。

¥The var statement declares function-scoped or globally-scoped variables, optionally initializing each to a value.

Try it

语法

¥Syntax

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

要声明的变量的名称。每个都必须是合法的 JavaScript identifier解构结合模式

valueN Optional

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

描述

¥Description

使用 var 声明的变量的范围是以下最接近包含 var 语句的大括号括起来的语法之一:

¥The scope of a variable declared with var is one of the following curly-brace-enclosed syntaxes that most closely contains the var statement:

或者如果以上都不适用:

¥Or if none of the above applies:

  • 当前的 module,用于在模块模式下运行的代码
  • 全局范围,用于在脚本模式下运行的代码。
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 声明的变量可以继续在块外引用。

¥Importantly, other block constructs, including block statements, try...catch, switch, headers of one of the for statements, do not create scopes for var, and variables declared with var inside such a block can continue to be referenced outside the block.

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

在脚本中,使用 var 声明的变量将添加为全局对象的不可配置属性。这意味着它的属性描述符无法更改,也无法使用 delete 删除它。JavaScript 具有自动内存管理功能,在全局变量上使用 delete 运算符是没有意义的。

¥In a script, a variable declared using var is added as a non-configurable property of the global object. This means its property descriptor cannot be changed and it cannot be deleted using delete. JavaScript has automatic memory management, and it would make no sense to be able to use the delete operator on a global variable.

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 模块 中,顶层变量声明的范围仅限于模块,并且不会作为属性添加到全局对象。

¥In both NodeJS CommonJS modules and native ECMAScript modules, top-level variable declarations are scoped to the module, and are not added as properties to the global object.

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

¥The list that follows the var keyword is called a binding list and is separated by commas, where the commas are not comma operators and the = signs are not assignment operators. Initializers of later variables can refer to earlier variables in the list and get the initialized value.

提升

¥Hoisting

var 声明,无论它们出现在脚本中的什么位置,都会在执行脚本中的任何代码之前进行处理。在代码中的任何位置声明变量相当于在顶部声明它。这也意味着变量可以在声明之前就已被使用。此行为称为 hoisting,因为变量声明似乎被移至发生该行为的函数、静态初始化块或脚本源的顶部。

¥var declarations, wherever they occur in a script, are processed before any code within the script is executed. Declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called hoisting, as it appears that the variable declaration is moved to the top of the function, static initialization block, or script source in which it occurs.

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

¥Note: var declarations are only hoisted to the top of the current script. If you have two <script> elements within one HTML, the first script cannot access variables declared by the second before the second script has been processed and executed.

js
bla = 2;
var bla;

这隐含地理解为:

¥This is implicitly understood as:

js
var bla;
bla = 2;

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

¥For that reason, it is recommended to always declare variables at the top of their scope (the top of global code and the top of function code) so it's clear which variables are scoped to the current function.

仅提升变量的声明,而不提升其初始化。仅当到达赋值语句时才会进行初始化。在此之前,变量仍为 undefined(但已声明):

¥Only a variable's declaration is hoisted, not its initialization. The initialization happens only when the assignment statement is reached. Until then the variable remains undefined (but declared):

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

这隐含地理解为:

¥This is implicitly understood as:

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

重新声明

¥Redeclarations

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

¥Duplicate variable declarations using var will not trigger an error, even in strict mode, and the variable will not lose its value, unless the declaration has an initializer.

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

var 声明也可以与 function 声明位于同一范围内。在这种情况下,var 声明的初始值设定项始终覆盖函数的值,无论它们的相对位置如何。这是因为函数声明在任何初始值设定项被评估之前被提升,因此初始值设定项稍后出现并覆盖该值。

¥var declarations can also be in the same scope as a function declaration. In this case, the var declaration's initializer always overrides the function's value, regardless of their relative position. This is because function declarations are hoisted before any initializer gets evaluated, so the initializer comes later and overrides the value.

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

var 声明不能与 letconstclassimport 声明位于同一范围内。

¥var declarations cannot be in the same scope as a let, const, class, or import declaration.

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

由于 var 声明的作用域不限于块,因此这也适用于以下情况:

¥Because var declarations are not scoped to blocks, this also applies to the following case:

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

它不适用于以下情况,其中 let 位于 var 的子作用域中,而不是同一作用域:

¥It does not apply to the following case, where let is in a child scope of var, not the same scope:

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

函数体内的 var 声明可以与参数具有相同的名称。

¥A var declaration within a function's body can have the same name as a parameter.

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

foo(2); // Logs 1

catch 块中的 var 声明可以与 catch 绑定标识符具有相同的名称,但前提是 catch 绑定是简单标识符,而不是解构模式。这是 不推荐使用的语法,你不应该依赖它。在这种情况下,声明被提升到 catch 块外部,但 catch 块内分配的任何值在外部都不可见。

¥A var declaration within a catch block can have the same name as the catch-bound identifier, but only if the catch binding is a simple identifier, not a destructuring pattern. This is a deprecated syntax and you should not rely on it. In this case, the declaration is hoisted to outside the catch block, but any value assigned within the catch block is not visible outside.

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

示例

¥Examples

声明并初始化两个变量

¥Declaring and initializing two variables

js
var a = 0,
  b = 0;

为两个变量分配单个字符串值

¥Assigning two variables with single string value

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

这相当于:

¥This is equivalent to:

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

请注意顺序:

¥Be mindful of the order:

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

此处,xy 在执行任何代码之前声明,但赋值稍后发生。在评估 x = y 时,y 存在,因此不会抛出 ReferenceError,其值为 undefined。因此,x 被分配了未定义的值。然后,将值 "A" 分配给 y

¥Here, x and y are declared before any code is executed, but the assignments occur later. At the time x = y is evaluated, y exists so no ReferenceError is thrown and its value is undefined. So, x is assigned the undefined value. Then, y is assigned the value "A".

几个变量的初始化

¥Initialization of several variables

请注意 var x = y = 1 语法 - y 实际上并未声明为变量,因此 y = 1不合格的标识符分配,它在非严格模式下创建全局变量。

¥Be careful of the var x = y = 1 syntax — y is not actually declared as a variable, so y = 1 is an unqualified identifier assignment, which creates a global variable in non-strict mode.

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!

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

¥The same example as above but with a strict mode:

js
"use strict";

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

console.log(x, y);

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

¥Implicit globals and outer function scope

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

¥Variables that appear to be implicit globals may be references to variables in an outer function scope:

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

带有解构的声明

¥Declaration with destructuring

每个 = 的左侧也可以是装订图案。这允许一次创建多个变量。

¥The left-hand side of each = can also be a binding pattern. This allows creating multiple variables at once.

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

欲了解更多信息,请参阅 解构赋值

¥For more information, see Destructuring assignment.

规范

Specification
ECMAScript Language Specification
# sec-variable-statement

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看

¥See also