Область видимости
1. Область видимости
Область видимости (scope) — это независимая от языка концепция, которая описывает доступность переменных в исполняемом коде.
Scope chain (цепочка областей видимости) - области видимости образуют иерархию, так что дочерние области имеют доступ к переменным из родительских областей, но не наоборот.
Переменная видна для исполняемого кода, если она есть в текущей области видимости или в цепочке областей видимости функции.
Есть три типа областей видимости:
Переменные, объявленные на самом верхнем уровне, то есть вне любых конструкций вроде
if,while,forи функций, находятся в глобальной области видимости.Переменные, объявленные внутри инструкций
if, циклов и других блоков кода находятся в блочной области видимости.Переменные, объявленные внутри функций, находятся в области видимости функции.
Это можно представить как дом с комнатами. Дом находится в глобальной области видимости. Каждая функция и блок создают новую комнату, вложенную внутрь дома. Переменные, объявленные внутри этих комнат, доступны только тогда, когда вы находитесь внутри этой комнаты. Вне комнаты эти переменные недоступны.
// Global scope
function foo() {
// Local function scope of foo
if (true) {
// Local block scope
}
// Local function scope of foo
function bar() {
// Local function scope of bar
}
// Local function scope of foo
}
// Global scope
CopyИнтерпретатор пытается сначала найти переменную в той области видимости, в которой к ней обратились. Если такой переменной в локальной области видимости нет, то он выходит наружу, на один уровень за попытку, пока не найдёт значение или не дойдет до самой верхней области видимости (глобальной) и поймет, что переменную с таким идентификатором невозможно найти, так как ее просто нет, тогда будет ошибка о том, что переменная не объявлена.
Функция add возвращает сумму a и b. Переменная a объявлена внутри функции, b нет.
Пытаясь решить выражение a + b, интерпретатор ищет значения a и b. Поиск начинается внутри локальной области видимости — внутри функции add. Он находит значение a и переходит к b. Невозможно найти значение b в локальной области видимости, поэтому поиск расширяется до наружной области. Тут он находит b — это 10. Выражение a + b превращается в 5 + 10, в результате получаем 15.
2. Область видимости функции
Как уже говорилось, функции создают собственную локальную область видимости. Переменные, созданные внутри функции, включая параметры, локальны внутри этой функции и не доступны коду из вне. Локальные переменные будут создаваться каждый раз при вызове функции, и их отдельные инкарнации никак друг с другом не связаны.
Глобальный value объявлен вне тела функции и его значение будет выведено в консоль. Локальный value внутри функции add по прежнему виден только внутри этой функции. Эти два value не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, не смотря на то, что у них одно и то же имя. В свою очередь innerValue не доступна вне тела функции.
Такое поведение помогает предотвратить случайное взаимодействие между функциями. Если бы все переменные использовались в любом месте программы, было бы очень трудно убедиться, что одна переменная не используется для разных операций.
Рассматривая локальные для функции переменные как существующие только внутри функции, язык делает возможным работу с функциями как с изолированными контейнерами, что позволяет не волноваться про весь код целиком.
3. Hoisting
В языках программирования, в том числе в JavaScript, код исполняется в две фазы.
Фаза компиляции, интерпретации или оценки (compile time, evaluation time) - подготовка перед исполнением кода, проверка валидности синтаксиса исходного кода.
Во время этой фазы компилятор или интерпретатор находит синтаксические ошибки, ошибки типизации и т. д. То есть код еще не выполняется, только оценивается. Если эта фаза прошла успешно, это как минимум значит, что в коде нет синтаксических ошибок и его можно запустить на исполнение.
Фаза исполнения (runtime) - скрипт начинает исполняться, выполняются инструкции вызовов функций и оценки выражений, происходит поиск необходимых идентификаторов в соответствующих областях видимости и тому подобное.
Если эта фаза завершилась успешно, значит скрипт написан без явных ошибок и закончил свою работу. На этой фазе могут быть ошибки, связанные с отсутствующими свойствами и переменными, преобразованием типов и т. д., то есть что-то, что происходит только во время выполнения кода.
Попробуйте выполнить следующий код. Так как мы сделали опечатку и вместо const пытаемся объявить переменную value ключевым словом cos, на фазе компиляции будет выявлена синтаксическая ошибка и фаза исполнения даже не запустится. В консоли мы сразу увидим сообщение об ошибке.
Поднятие переменных (hoisting) - это механизм интерпретатора, который, до фазы исполнения кода, поднимает объявления переменных в начало области видимости (блочной или функции) в которой они были объявлены.
Именно поэтому работает function declaration и так странно ведут себя переменные, объявленные используя var - их объявления поднимаются в начало области видимости функции в которой они были объявлены.
Переменные, объявленные используя let или const так же поднимаются, но при этом подчиняются блочной области видимости, ничем не инициализируются по умолчанию и не доступны для обращения до того места в коде, где были объявлены в коде.
Более детально про поднятие идентификаторов и ключевые словах var, let и const читайте в этой статье.
Last updated