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

瀏覽器相容性

另見