var

Інструкція var (змінна) оголошує змінні функційної або глобальної області видимості, за необхідності ініціалізуючи їх значеннями.

Спробуйте його в дії

Синтаксис

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:

Або, якщо жодний з вищезазначених варіантів не підходить:

  • Поточний модуль – у випадку коду, що виконується в режимі модуля
  • Глобальна область видимості – у випадку коду, що виконується в режимі сценарію.
function foo() {
  var x = 1;
  function bar() {
    var y = 2;
    console.log(x); // 1 (функція `bar` замикається над `x`)
    console.log(y); // 2 (`y` – в області видимості)
  }
  bar();
  console.log(x); // 1 (`x` – в області видимості)
  console.log(y); // ReferenceError: `y` обмежена областю видимості `bar`
}

foo();

Важливо те, що інші блокові конструкції, серед яких блокові інструкції, try...catch, switch, заголовки усіх інструкцій for, не утворюють областей видимості для var, і до змінних, оголошених з var усередині такого блоку, можна звертатися поза цим блоком.

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

У сценарії змінна, оголошена за допомогою var, додається як неналаштовна властивість глобального об'єкта. Це означає, що її дескриптор властивості не можна змінювати, і її не можна видалити за допомогою delete. JavaScript має автоматичне керування пам'яттю, і немає сенсу використовувати оператор delete на глобальній змінній.

"use strict";
var x = 1;
Object.hasOwn(globalThis, "x"); // true
delete globalThis.x; // У суворому режимі – TypeError. Без нього – нічого не робить.
delete x; // У суворому режимі – SyntaxError. Без нього – нічого не робить.

І в модулях CommonJS NodeJS, і в нативних модулях ECMAScript оголошення змінних вищого рівня мають за область видимості свій модуль, а не додаються як властивості до глобального об'єкта.

Список після ключового слова var зветься списком зв'язування, він розділюється комами, де коми – це оператори коми, а знаки = – це не оператори присвоєння. Ініціалізатори пізніших змінних можуть посилатися на раніше оголошені змінні й отримувати їхні значення.

Піднімання

Оголошення var, щоразу, коли вони зустрічаються в сценарії, обробляються до виконання будь-якого коду сценарію. Оголошення змінної будь-де в коді рівносильне оголошенню її нагорі. Також це означає, що може здаватися, ніби змінна використовується до свого оголошення. Така логіка зветься підніманням, адже здається, ніби оголошення змінної перенесено нагору функції, блоку статичної ініціалізації чи вихідного коду сценарію, в якому воно зустрілося.

[!NOTE] Оголошення var піднімаються лише нагору поточного сценарію. Якщо в одному HTML є два елементи <script>, то перший сценарій не може звертатися до змінних, оголошених другим, поки другий сценарій не буде оброблений та виконаний.

bla = 2;
var bla;

Це неявно розуміється як:

var bla;
bla = 2;

У зв'язку з цим радять завжди оголошувати змінні нагорі їхньої області видимості (нагорі глобального коду та нагорі коду функції), щоб було ясно, які змінні належать до області видимості поточної функції.

Лише оголошення змінної підіймається, але не її ініціалізація. Вона відбувається лише тоді, коли доходить до інструкції присвоєння. Доти змінна залишається undefined (але оголошеною):

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

Неявно це розуміється як:

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

Повторне оголошення

Дублювання оголошення змінних за допомогою var не спричиняють помилок, навіть у суворому режимі, і змінна не втратить свого значення, якщо оголошення не має ініціалізатора.

var a = 1;
var a = 2;
console.log(a); // 2
var a;
console.log(a); // 2; не undefined

Оголошення var також можуть бути в тій же області видимості, що й оголошення function. У такому випадку ініціалізатор оголошення var завжди відкидає значення функції, незалежно від послідовності цих оголошень. Це пов'язано з тим, що оголошення функцій підіймаються до виконання будь-яких ініціалізаторів, тож ініціалізатор спрацьовує пізніше та затирає значення функції.

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

Оголошення var не можуть бути в тій же області видимості, що й оголошення let, const, class або import.

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

У зв'язку з тим, що оголошення var не обмежують свою область видимості блоками, це також спрацьовує в наступному випадку:

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

Це не застосовується в наступному випадку, в якому let перебуває в дочірній області видимості відносно області var, а не в тій же самій:

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

Оголошення var в тілі функції може мати те саме ім'я, що й параметр.

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

foo(2); // Виводить 1

Оголошення var у блоку catch може мати таке ж ім'я, що й зв'язаний catch ідентифікатор, але лише тоді, коли зв'язування catch є простим ідентифікатором, а не патерном деструктурування. Це нерекомендований запис, на нього не слід покладатися. У такому випадку оголошення піднімається назовні блоку catch, але значення, присвоєне у блоку catch, не є видимим назовні.

try {
  throw 1;
} catch (e) {
  var e = 2; // Працює
}
console.log(e); // undefined

Приклади

Оголошення та ініціалізація двох змінних

var a = 0,
  b = 0;

Присвоєння двом змінним одного рядкового значення

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

Це рівносильно:

var a, b = a = "A";

Слідкуйте за послідовністю оголошень:

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

Тут x і y оголошені до виконання будь-якого коду, а присвоєння відбувається пізніше. На момент виконання x = y, y існує, тому ReferenceError не виникає, а її значення дорівнює undefined. Таким чином, x отримує значення undefined. Потім y отримує значення "A".

Ініціалізація декількох змінних

Будьте уважні з записом var x = y = 1: y фактично не оголошується як змінна, тому y = 1 є присвоєнням некваліфікованого ідентифікатора, яке в несуворому режимі створює глобальну змінну.

var x = 0;
function f() {
  var x = y = 1; // Оголошує x локально; оголошує y глобально.
}
f();

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

// У несуворому режимі:
// x – глобальна, як і очікувалося;
// проте y – витікає поза функцію!

Той самий приклад, що й вище, але в суворому режимі:

"use strict";

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

console.log(x, y);

Неявні глобальні змінні та область видимості навколо функції

Змінні, що здаються неявно глобальними, можуть бути звертаннями до змінних в області видимості навколо функції:

var x = 0; // Оголошує x в області видимості файлу, а тоді присвоює їй значення 0.

console.log(typeof z); // "undefined", оскільки z ще не існує

function a() {
  var y = 2; // Оголошує y в області видимості функції a, а потім присвоює їй значення 2.

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

  function b() {
    x = 3; // Присвоює 3 наявній x з файловою областю видимості.
    y = 4; // Присвоює 4 наявній зовнішній y.
    z = 5; // Створює нову глобальну змінну z, а тоді присвоює їй значення 5.
    // (Викидає ReferenceError у суворому режимі.)
  }

  b(); // Створює z як глобальну змінну.
  console.log(x, y, z); // 3 4 5
}

a(); // Також викликає b.
console.log(x, z); // 3 5
console.log(typeof y); // "undefined", оскільки y є локальною для функції a

Оголошення з деструктуруванням

Лівий бік кожного = також може бути патерном зв'язування. Це дає змогу створювати кілька змінних за раз.

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

Більше про це - в Присвоєнні з деструктуруванням.

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
var
Chrome Full support 1
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support 3
Opera Full support 3
Safari Full support 1
WebView Android Full support 1
Chrome Android Full support 18
Firefox for Android Full support 4
Opera Android Full support 10.1
Safari on iOS Full support 1
Samsung Internet Full support 1.0
Deno Full support 1.0
Node.js Full support 0.10.0

Дивіться також