Хабрахабр

[Перевод] Среда, лексическая область видимости и замыкания в JavaScript

Перевод JavaScript Environment, Lexical Scope and Closures.

Наша огромная планета одна на всех. Поговорим о среде. Можно сказать, что среда и микроклимат этого завода изолированы от внешней среды. При строительстве нового химического завода было бы неплохо его изолировать, чтобы все внутренние процессы не покидали его пределы.

То, что вы создаете снаружи — внешние функции, условные операторы, циклы и другие блоки — представляет собой внешнюю, глобальную среду.
Аналогичным образом устроена программа.

Эти компоненты обладают глобальной областью видимости. Постоянная age, функция multiplier и переменная result находятся во внешней среде. Область видимости — это область, в которой доступен компонент.

Поскольку она находится внутри блока кода, она представляет собой локальную константу, а не глобальную. В данном случае x является константой внутри функции multiplier. Она видна только внутри функции, но не снаружи — её область видимости локальна.

Определить его сложнее, чем постоянную или переменную, но он ведет себя примерно как локальная переменная. Функция multiplier обладает еще одним компонентом из локальной области видимости — это аргумент num.

У нас нет внешнего доступа к x — его как будто не существует:

В результате мы получили ReferenceError. console.log вызвал x в глобальной среде, в которой тот не определен.

Мы можем задать x глобально:

Эти x никак не связаны — они находятся в разных средах. У нас появился глобальный x с известным значением, но локальный x в функции multiplier по-прежнему виден только изнутри. Несмотря на одинаковое название, они не смешиваются.

Вот пример использования if: Любой блок кода в фигурных скобках становится локальной средой.

То же происходит с циклами while и for.

То есть, глобальный — это видимый повсюду, даже внутри объектов? Итак, локальный — значит, невидимый снаружи. Да!

Функция начинает действовать только при вызове, а не при определении, поэтому изначально a=0, а при вызове changer принимает значение 1. Глобальная переменная a изменилась внутри функции changer.

Глобальные переменные делают ваш код крайне хрупким, любой элемент может сломать любой другой в любой момент. Легко поддаться соблазну и поместить всё в глобальную область видимости, забыв о всех сложностях отдельных сред — но это ужасная идея. Поэтому не пользуйтесь глобальной областью видимости и держите всё на местах.

Часть II. Лексическая область видимости

Взгляните на эту программу:

a задана внутри, а b нет. Функция multiplier возвращает продукты a и b.

Он начинает поиск внутри, а затем выходит наружу, изучая одну область за другой, пока не находит то, что искал, или не понимает, что это невозможно найти. При попытке произвести операцию умножения a*b, JavaScript ищет значения a и b.

Он тут же находит значение и переходит к b. Следовательно, в этом примере JavaScript начинает поиски a внутри локальной области — внутри функции multiplier. Там он узнаёт, что b равняется 10. b в локальной среде он не найдет, поэтому выходит за её пределы. Значит, a*b превращается в 5*10, а затем в 50.

Не найдя b в первом слое, JavaScript продолжил бы поиски всё в новых и новых слоях, всё дальше и дальше. Этот кусок кода мог бы находиться внутри другой функции, которая также находится внутри другой функции.

Обратите внимание, что a=7 никак не влияет на результат вычислений: значение a нашлось внутри, поэтому внешняя a роли не играет.

Область видимости любого компонента определяется местоположением этого компонента в коде, а у вложенных блоков имеется доступ к внешним областям. Это называется лексической областью видимости.

Часть III. Замыкания

Среды и области видимости поддерживаются большинством языков программирования, и этот механизм позволяет вводить замыкания. Замыкание по своей сути — функция, которая «запоминает» внешние сущности, использованные внутри.

Прежде чем продолжить, давайте вспомним, как создаются и используются функции:

Набор состоит из двух частей — константы и самой функции. f — довольно бесполезная функция, всегда возвращающая 0.

Первый компонент — константа под названием f. Важно помнить, что это отдельные компоненты. В данном случае значением является функция. Её значением может быть число или строковое значение.

Таким образом, f — лист бумаги, на одной стороне которого написано f, а на другой — описание запускаемой функции. В прошлых уроках мы приводили аналогию: константы похожи на листы бумаги с названием на одной стороне и значением на другой.

При вызове этой функции:

Создается новое поле на основе описания с листа бумаги.

Вот пример кода. Вернемся к замыканиям.

Обе локальны по отношению к функции createPrinter и доступны только внутри неё. Функция createPrinter создает константу name, а затем функцию под названием printName.

У самой printName локальных компонентов нет, но есть доступ к области видимости, где она создается, и к внешней среде, где постоянной присваивается name.

Напоминаем, что определения функций представляют собой описание запущенных функций, это просто элементы данных, как числа или цепочки. Функция createPrinter возвращает функцию printName. Следовательно, мы может вернуть определение функции так же, как возвращаем числа.

Возвращается функция, так что myPrinter также становится функцией. Во внешней области мы создаем константу myPrinter и задаем возвращаемое ей значение как createPrinter. При её вызове на экране появится King.

Функция была вызвана и выполнена. Вот что забавно: константа name была создана внутри функции createPrinter. Волшебный ящик Пандоры пропадает вместе со всем содержимым. Как известно, когда функция заканчивает работу, она прекращает существование.

Таким образом, при вызове myPrinter мы получили King — значение, которое функция помнит, несмотря на то, что эта область больше не существует. Но он вернул другую функцию, которая каким-то образом запомнила константу name.

Замыкание — комбинация функции и среды, в которой она была определена. Функция, которую возвращает createPrinter, называется замыканием. Функция «замкнула» в себе определенную информацию, полученную в области видимости.

Сам принцип возвращения функций подобно возвращению чисел и строковых значений предоставляет вам больше свободы для маневра. Это может показаться странной причудой JavaScript, но разумное использование замыканий может помочь сделать код более приятным, чистым и читабельным.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть