Если вы посмотрите свой обычный английский словарь, вы можете найти следующее прямо рядом с «закрытием»;

чувство или действие завершения неприятной ситуации, времени или опыта, чтобы вы могли начать новую деятельность:

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

Итак, что такое замыкания в Javascript?

Замыкания в Javascript - это не что иное, как функции с сохраненными данными. Замыкание - это функция, которая имеет доступ к переменным, определенным во внешней функции, которые были ранее возвращены.

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

Как видно выше, функция external напрямую возвращает анонимную стрелочную функцию, которая возвращает две строковые переменные и объединяет их. Но обратите внимание на то, где определены эти outerData и innerData. outerData находится в области внешней функции, тогда как innerData находится в области действия анонимной стрелочной функции.

Если мы вызовем функцию external, мы получим следующее:

>> outer()
> () => {
        let innerData = " and this is inner"
        return outerData + innerData
    }

Что ж, это не удивительно, он возвращает анонимную стрелочную функцию. Но обратите внимание, что эта функция использует переменную outerData, которая была определена в функции external. Итак, давайте рассмотрим, что произошло, шаг за шагом;

1 - создается новая переменная outerData.

2 - return возвращает все тело анонимной стрелочной функции.

3 - external функция завершает свое выполнение, и все переменные в области действия функции, в нашем случае outerData, больше не существуют. (Переменные внутри функций возникают только тогда, когда функция работает, и перестают существовать, когда функции завершают выполнение.)

Если мы немедленно вызовем возвращенную функцию;

>> outer()()
> "This is outer and this is inner"

1- создается новая переменная innerData.

2 - JS попытается собрать вместе innerData и outerData в возвращении. У него есть информация о innerData, потому что он только что создал его. Но externalData там вообще не должно быть, функция external выполняется перед внутренней анонимной стрелочной функцией, любые переменные в области действия функции outer больше не определены.

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

Давайте посмотрим на другой пример,

Внутренняя анонимная стрелочная функция использует переменную x, которая была определена в функции external, и к моменту ее вызова функция external вернулась. Как и в предыдущем примере, здесь анонимная стрелочная функция является закрытием.

На самом деле вы можете увидеть объем своей функции, используя console.dir (), используйте для этого консоль Google Chrome.

> k = outer(4)
> console.dir(k)

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

Так зачем нам замыкания в Javascript?

Лучшее преимущество использования замыканий состоит в том, что они позволяют нам создавать частные переменные, давайте посмотрим на следующее:

>> let letsCount = counter()
>> letsCount()
> 1
>> letsCount()
> 2
>> letsCount()
> 3
>> count
> Uncaught ReferenceError: count is not defined(...)

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

Теперь перейдем к более сложному примеру;

Предположим, это функция для наших еженедельных покупок продуктов. У нас есть переменная buyList, которая содержит товары, которые мы всегда покупаем, когда идем за покупками. Это наша частная переменная, к которой у нас нет доступа извне. Вместо того, чтобы возвращать одну функцию, мы возвращаем объект с двумя методами внутри, которые в любом случае являются функциями.

Теперь мы собираемся смоделировать две разные недели походов за продуктами.

>> let week1 = shoppingList()
>> let week2 = shoppingList()
>> week1.getList()
> ["Milk","Bread","Eggs"]
>> week1.addToList("Onions")
> ["Milk,"Bread","Eggs","Onions"]
>> week2.getList()
> ["Milk","Bread","Eggs"]

Как видно выше, любые изменения в списке покупок week1 не влияют на список покупок week2, потому что они не имеют той же области действия.

Заключение

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

Из этой статьи можно сделать два важных вывода;

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

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

Надеюсь, эта статья пригодится, увидимся в других статьях!