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 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |