Область видимости
1. Область видимости
Область видимости (scope) — это независимая от языка концепция, которая описывает доступность переменных в исполняемом коде.
Scope chain (цепочка областей видимости) - области видимости образуют иерархию, так что дочерние области имеют доступ к переменным из родительских областей, но не наоборот.
Переменная видна для исполняемого кода, если она есть в текущей области видимости или в цепочке областей видимости функции.
Есть три типа областей видимости:
Переменные, объявленные на самом верхнем уровне, то есть вне любых конструкций вроде
if
,while
,for
и функций, находятся в глобальной области видимости.Переменные, объявленные внутри инструкций
if
, циклов и других блоков кода находятся в блочной области видимости.Переменные, объявленные внутри функций, находятся в области видимости функции.
Это можно представить как дом с комнатами. Дом находится в глобальной области видимости. Каждая функция и блок создают новую комнату, вложенную внутрь дома. Переменные, объявленные внутри этих комнат, доступны только тогда, когда вы находитесь внутри этой комнаты. Вне комнаты эти переменные недоступны.
Интерпретатор пытается сначала найти переменную в той области видимости, в которой к ней обратились. Если такой переменной в локальной области видимости нет, то он выходит наружу, на один уровень за попытку, пока не найдёт значение или не дойдет до самой верхней области видимости (глобальной) и поймет, что переменную с таким идентификатором невозможно найти, так как ее просто нет, тогда будет ошибка о том, что переменная не объявлена.
Функция 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
так же поднимаются, но при этом подчиняются блочной области видимости, ничем не инициализируются по умолчанию и не доступны для обращения до того места в коде, где были объявлены в коде.
Last updated