В этом уроке я хочу рассказать о том, что такое цепь областей видимости.
У нас имеется следующий код:
function b() {
console.log(user);
}
function a() {
var user = "qqc";
b();
}
var user = "golos";
a();
Скрипт почти такой, как и в предыдущем уроке, разве что убрали объявление переменной user
из функции b
и оставили лишь один вывод в консоль. Как думаете, что отобразится в консоли?
Немного вспомним: когда вызывается функция b
, создаётся новый контекст выполнения, кладётся в стек вызовов, а все объявленные переменные отправляются в переменное окружение (variable environment). Но, в нашем случае, переменная u
в функции b
, где мы хотим её отобразить, не объявлена.
Неожиданно, правда? А где жеundefined
? Ну илиqqc
, ведь это было последним присвоением перед вызовом функцииb
?
В консоли мы увидели golos
- значение переменной, "живущей" на глобальном уровне.
Когда мы обращаемся к переменной, JavaScript не просто просматривает переменное окружение в текущем контексте выполнения. Я уже упоминала мельком понятие внешнего окружения.
Получается, когда интерпретатор пытается получить доступ к переменной, он сначала проверяет, есть ли такая переменная в текущем контексте выполения, и, если её нет, отправляется на поиски во внешнее переменное окружение. В нашем случае, на глобальном уровне.
Но почему? Ведь мы функциюb
вызываем из функцииa
, почему внешним окружением стал не контекст выполнения этой функции?
Лексически функция b
находится в глобальном контексте выполнения, не внутри функции a
. То есть на том же уровне, что и строка var user = 'golos'
.
Когда мы вызываем функцию, ссылка на внешнее окружение записывается, ведь синтаксический парсер уже пробежал и запомнил, на каком уровне, где какая переменная и функция создается. Эта ссылка сохраняется в скрытом свойстве функции [[Scope]]
.
Такие ссылки, образующие цепочки, называются цепью областей видимости (scope chain). Напомню, что область видимости - это та часть кода, в которой мы имеем доступ к переменным.
Немного изменим код:
function a() {
function b() {
console.log(user);
}
var user = "qqc";
b();
}
var user = "golos";
a();
Мы изменили лексическое окружение функции b
.
Когда мы запустим наше приложение, мы увидим в консоли qqc
, потому как теперь лексически функция b
"живёт" внутри функции a
, соответственно, не найдя внутри себя переменной user
, отправится на внешний слой - теперь это функция a
.
Еще немного изменений:
function a() {
function b() {
console.log(user);
}
b();
}
var user = "golos";
a();
В консоли снова golos
.
Когда выполнялась функция b
, она поискала у себя переменную, отправилась искать её во внешнее окружение - в функцию a
, но и там такой переменной не оказалось, и она отправилась во внешнее окружение функции a
- глобальный контекст выполнения.
Голосуйте за моего делегата здесь. Для этого нужно нажать на стрелочку рядом с моим ником qqc
. Спасибо за поддержку! 🙏🌸
Привет!
Этот пост был выбран Академией Голоса и попал в список программы поддержки качественных образовательных постов.
Ссылка на твой пост будет опубликована в отчете Академии.
Спасибо за полезный контент (ノ◕ヮ◕)ノ*:・゚✧
@qqc, Поздравляю!,
Ваш пост был упомянут в моем хит-параде в следующей категории: