Замыкание в JavaScript

Замыкание функции — это комбинация функции и лексического окружения, в котором эта функция была определена; замыкание обеспечивает доступ внутренней функции к области видимости (Scope) внешней функции (при этом переменные внутренней функции для внешнего окружения недоступны).

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

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

Выполняющуюся функцию можно рассматривать как объект в памяти; переменные функции - это свойства этого объекта. Когда обычная функция завершает свое выполнение, то освобождает память, которую занимала, если на её переменные не осталось ссылок.

При замыкании внутренняя функция может использовать свойства объекта внешней функции, что препятствует удалению объекта (переменных) внешней функции из памяти  (стека выполнения) (внешняя переменная "замыкается" внутренней функцией).

Замыкание позволяет:

  • ограничить доступ к данным (ограничить их область видимости);
  • создать своеобразное автономное хранилище данных.

Требования для организации замыкания функции:

  1. Наличие внешней окружающей функции, которая вызывается хотя бы раз (без вызова внешней функции не будут созданы ни её внутренняя область видимости, ни замыкание).
  2. Внешняя окружающая функция должна возвращать хотя бы одну внутреннюю функцию, использующую лексическое окружение внешней функции.

Ниже пример функции createGenerator(), которая создает другую функцию genNewID() с приватным состоянием. Каждый раз, когда мы вызываем createGenerator(), функцией genNewID() запоминается индекс последнего вызова index и возвращается строка с номером текущего вызова.

Рассмотрим пример:

Таким образом, замыкание позволяет обходить общее правило областей видимости JS (дочерние области имеют доступ к родительским областям, но не наоборот).  Функция корректно вызывается извне ее лексической области видимости, определенной на этапе разработки. Замыкание дает возможность организовать доступ к приватной области видимости с помощью функции, находящейся в дочерней области видимости.

Подробнее

У функции bar() есть доступ в лексической области видимости к внутренней области видимости foo(). Но в то же время, мы берем функцию bar() и передаем ее как значение. В этом случае мы возвращаем сам объект функции, на который ссылается bar.

После выполнения foo() мы присвоим значение, которая она возвращает ( внутреннюю функцию bar() ) в переменную baz. Соответственно, вызов baz() приведет к вызову функции bar() (просто с помощью другой ссылки в идентификаторе).

bar() выполнится снаружи относительно своей объявленной лексической области видимости.

После выполнения foo() обычно мы ожидаем, что вся внутренняя область видимости foo() целиком будет удалена сборщиком мусора, который исследует и освобождает память, которая больше не используется. Но замыкание не даст этому произойти, так как эта внутренняя область видимости на самом деле все еще используется функцией bar() через вызов baz().

Таким образом функция bar() вызывается корректно вне ее лексической области видимости, определенной на этапе разработки. Замыкание дает возможность функции продлить доступ к лексической области видимости, которая была определена на этапе разработки.

[свернуть]

Одним из важных применений замыканий является хранение приватной ссылки на переменную из внешней области видимости:

Эта техника обеспечивает функции эксклюзивный доступ к переменным login и pass, и в то же время приводит к недоступности переменных login и pass извне (с родительского уровня области видимости).

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.