Closures
Замыкание — это комбинация функции и лексического окружения, в котором эта функция была определена.
Лексическая область видимости
Рассмотрим следующий пример:
init()
создает локальную переменнуюname
и определяет функциюdisplayName()
.displayName()
— это внутренняя функция, она определена внутри init()
и доступна только внутри тела init()
. ФункцияdisplayName()
не имеет собственных локальных переменных и вместо этого использует переменнуюname
, определенную в родительской функции. Однако точно такие же локальные переменные могут создаваться и использоваться внутри displayName()
.
Выполните этот код и обратите внимание, что команда alert()
внутри displayName()
благополучно выводит на экран содержимое переменнойname
, объявленной в родительской функции. Это пример так называемой лексической области видимости (lexical scoping): в JavaScript область действия переменной определяется по ее расположению в коде (это очевидно лексически), и вложенные функции имеют доступ к переменным, объявленным вовне. Этот механизм и называется Lexical scoping (область действия, ограниченная лексически).
Замыкание
Рассмотрим следующий пример:
Если выполнить этот код, то результат будет такой же, как и выполнение init()
из предыдущего примера: строка "Mozilla" будет показана в JavaScript alert диалоге. Что отличает этот код и представляет для нас интерес, так это то, что внутренняя функция displayName() была возвращена из внешней до того, как была выполнена.
На первый взгляд кажется не очевидным, что этот код правильный, но он работает. В некоторых языках программирования локальные переменные функции существуют только во время выполнения этой функции. После завершения выполнения makeFunc()
можно ожидать, что переменная name больше не будет доступна. Однако, поскольку код продолжает нормально работать, очевидно, что это не так в случае JavaScript.
Причина в том, что функции в JavaScript формируют так называемые замыкания. Замыкание — это комбинация функции и её лексического окружения, в котором эта функция была объявлена. Это окружение состоит из произвольного количества локальных переменных, которые были в области действия функции во время создания замыкания. В рассмотренном примере, myFunc
— это ссылка на экземпляр функции displayName
, созданной в результате выполнения makeFunc.
Экземпляр функции displayName
, в свою очередь, сохраняет ссылку на свое лексическое окружение, в котором есть переменная name
. По этой причине, когда происходит вызов функции myFunc
, переменная name
остается доступной для использования, и сохраненный в ней текст "Mozilla" передаётся в alert
.
А вот немного более интересный пример — функция makeAdder
:
Здесь мы определили функцию makeAdder(x)
, которая получает единственный аргумент x
и возвращает новую функцию. Эта функция получает единственный аргумент y
и возвращает сумму x
и y
.
По существу, makeAdder
вместо этого — фабрика функций, она создает функции, которые могут прибавлять определенное значение к своему аргументу. В примере выше мы используем нашу фабричную функцию для создания двух новых функций — одна прибавляет 5 к своему аргументу, вторая прибавляет 10.
add5
и add10
— это примеры замыканий. Эти функции делят одно определение тела функции, но при этом они сохраняют различные окружения. В окружении функции add5x
— это 5, в то время как в окружении add10x
— это 10.
Last updated