JavaScript: Область видимости переменных
- Глобальные переменные
- Локальные переменные
- Блочные переменные
- Повторное объявление
- Цепочка областей видимости
- Подъём объявлений
В JavaScript есть три области видимости: глобальная, область видимости функции и блочная. Область видимости переменной – это участок исходного кода программы, в котором переменные и функции видны и их можно использовать. Глобальную область видимости иначе ещё называют кодом верхнего уровня.
Глобальные переменные
Переменная, объявленная вне функции или блока, называется глобальной. Глобальная переменная доступна в любом месте исходного кода:
var num = 5; function foo() { console.log(num); } foo(); // 5 console.log(num); // 5 { console.log(num); // 5 }
Локальные переменные
Переменная, объявленная внутри функции, называется локальной. Локальная переменная доступна в любом месте внутри тела функции, в которой она была объявлена. Локальная переменная создаётся каждый раз заново при вызове функции и уничтожается при выходе из неё (при завершении работы функции):
function foo() { var num = 5; console.log(num); } foo(); // 5 console.log(typeof num); // undefined
Локальная переменная имеет преимущество перед глобальной переменной с тем же именем, это означает, что внутри функции будет использоваться локальная переменная, а не глобальная:
var x = "глобальная"; // Глобальная переменная function checkscope() { var x = "локальная"; // Локальная переменная с тем же именем, что и у глобальной document.write(x); // Используется локальная переменная, а не глобальная } checkscope(); // => "локальная"Попробовать »
Блочные переменные
Переменная, объявленная внутри блока с помощью ключевого слова let
, называется блочной. Блочная переменная доступна в любом месте внутри блока, в котором она была объявлена:
let num = 0; { let num = 5; console.log(num); // 5 { let num = 10; console.log(num); // 10 } console.log(num); // 5 } console.log(num); // 0
Повторное объявление
Если с помощью ключевого слова var
повторно объявить переменную с тем же именем (в той же области видимости), то ничего не произойдёт:
var a = 10; var a; console.log(a); // 10
Если повторное объявление сопровождается инициализацией, то такая инструкция действует как обычное присваивание нового значения:
var a = 10; var a = 5; // Тоже самое, что и a = 5; console.log(a); // 5
Если с помощью ключевого слова let
повторно объявить переменную с тем же именем (в той же области видимости), то будет вызвана ошибка:
var a = 10; let a; // Ошибка.
Цепочка областей видимости
Рассмотрим следующий пример:
var num = 5; function foo() { var num2 = 10; function bar() { var num3 = 15; } }
В этом коде три области видимости: глобальная, область видимости функции foo()
и область видимости функции bar()
. В глобальной области видимости определены переменная num
и функция foo()
. В области видимости функции foo()
определены переменная num2
и функция bar()
, в ней также доступна переменная num
из глобальной области видимости. Область видимости функции bar()
содержит одну переменную num3
, которая доступна только внутри функции bar()
. В области видимости функции bar()
также доступны переменные из двух других областей, потому что они являются родительскими по отношению к ней. Цепочка областей видимости для этого примера представлена на рисунке ниже:
На рисунке разные области видимости показаны прямоугольниками разного цвета. Внутренней области видимости в цепочке областей видимости доступно всё из внешних областей, но внешним областям не доступно ничего из внутренних областей видимости.
Цепочка областей видимости упорядочена. Интерпретатор производит поиск идентификаторов в цепочке областей видимости по направлению наружу, но не внутрь. Это означает, что поиск имени начинается с той области видимости, где было выполнено обращение к идентификатору. Если имя идентификатора обнаруживается, поиск прекращается. Если в текущей области видимости найти имя не удалось, выполняется поиск в следующей (во внешней) области видимости и т. д. Таким образом, будет использован идентификатор из той области видимости, в которой был найден. Если идентификатор не будет найден ни в одной из областей видимости JavaScript сгенерирует ошибку:
var str = "глобальная"; var num = 5; function foo() { var str = "локальная"; // Используется локальная переменная str num = 10; // Используется глобальная переменная num // alert(x); // Ошибка. Переменной x нет ни в одной области видимости } foo(); alert(str); // "глобальная" alert(num); // 10
Если в теле функции необъявленной переменной присвоить значение то, в момент вызова функции, если в глобальной области видимости нет переменной с таким именем, будет создана новая глобальная переменная:
function foo() { num = 2; } foo(); // Создана новая глобальная переменная num alert(num); // 2
Подъём объявлений
В JavaScript объявленные переменные доступны в любом месте относительно своей области видимости, это означает, что переменные оказываются видимы ещё до того, как будут объявлены в коде. Эта особенность JavaScript неофициально называется подъёмом
: программный код ведёт себя так, как если бы объявления переменных неявно поднимались
(без инициализации) на самый верх относительно своей области видимости.
Рассмотрим следующий фрагмент кода:
var str = "глобальная"; function foo() { alert(str); // undefined var str = "локальная"; alert(str); // "локальная" } foo();
Посмотрев на код, можно было бы подумать, что первый alert
должен вывести строку "глобальная", потому что объявление локальной переменной str
ещё не было выполнено. Однако, на деле выводится значение undefined
. Благодаря подъёму
объявлений функция выше эквивалентна реализации, приведённой ниже, в которой объявление переменной поднято
в начало функции:
function foo() { var str; // Объявление локальной переменной в начале функции alert(str); // Здесь она доступна, но не инициализирована str = "локальная"; // Здесь она инициализируется alert(str); // А здесь она имеет ожидаемое значение – "локальная" }
Тоже самое касается и глобальной области видимости, переменная объявленная снизу, доступна наверху:
alert(num); // undefined var num = 10; alert(num); // 10
С этой темой смотрят: