Добро пожаловать в пятую часть серии YDKJS. Часть 4 вы можете найти здесь. Как сказано в первой части, эта серия основана на моих уроках из легендарной серии книг Вы не знаете JS Кайла Симпсона и серии Javascript Каушика Котагала из Javabrains .

Здесь мы начнем с одной из самых сложных тем, связанных с Javascript, то есть Замыкания. Но нужно знать, что замыкания повсюду в JS.

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

Выше приведен простой пример внутреннего () внутри внешнего (). Внутренний () объявляется и выполняется изнутри внешней функции.

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

Итак, мы изменили внутреннее выражение на выражение функции и вернули его. Итак, когда мы вызываем external, мы можем сохранить возвращаемое значение в переменной innerFn.

Давайте поймем одну вещь. Переменная b имеет область видимости во внешней функции, то есть от строки 4 до строки 10. Итак, в строке 13, когда мы вызываем внешнюю функцию, она может получить доступ к значению b, но в строке 14 внешней функции нет.

Итак, как же innerFn () получает доступ к значению b. Здесь в игру вступает JS-функция Closures. Когда var inner создается в строке 6, JS-движок сохраняет не только информацию об объекте функции, но и информацию о его области видимости. Таким образом, он хранит область видимости переменных a и b внутри объекта внутренней функции.
Теперь не имеет значения, где вы вызываете inner, будь то в этом файле или в каком-то стороннем файле. Он всегда будет помнить значения a и b, как если бы был сделан снимок.

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

Еще нужно знать, если мы вызовем external 2 раза, то сколько копий a и b будет создано.

Как показано выше, во внутреннюю строку добавлена ​​строка для увеличения переменных a и b. Теперь, поскольку a является глобальной переменной, ее значение равно 11 в первый раз и 12 во второй раз, тогда вызывается innerFn2.

Но у b есть снимок во внутренней функции, поэтому каждый новый вызов через новый innerFn будет начинать b с 20 и печатать его как 21 из-за приращения.

Давайте теперь посмотрим на практический пример закрытия. Javascript является однопоточным, поэтому, если мы хотим, чтобы наша проблема подождала, мы используем функцию setTimeout, предоставляемую JS.

Здесь setTimeout в строке 7 вызывает функцию fn. Эта функция fn представляет собой консольное выражение функции, записывающее переменную a. Теперь, когда этот fn создается, он получает снимок переменной a, и даже если setTimeout вызывается из другого файла, не имеющего понятия var a, эта переменная получает печать с задержкой в ​​6 секунд.

Теперь давайте рассмотрим другое практическое использование замыканий. У нас есть концепция геттеров и сеттеров в объектно-ориентированных языках, таких как Java. Таким образом мы скрываем переменные от внешнего мира в функции / классе и делаем их закрытыми. Доступ к ним возможен только через методы получения и установка через методы установки.

Попробую создать их на Javascript. Рассмотрим нашу первую попытку ниже.

Здесь мы создали объект person, у которого есть два свойства firstName и lastName, содержащие значение. Затем два метода получения getFirstName и getLastname для получения этих значений.
Как видно из консоли, мы можем выполнить person. getFirstName (), но мы также можем выполнить команду person < / abuse.<▪firstName
У нас не должно быть такой возможности, но у нас нет концепции частных переменных в Javascript, как в Java.

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

Сначала мы помещаем объект в функцию createPerson. Затем мы перемещаем переменные firstName и lastName за пределы объекта. У нас есть обычные getFirstName и getLastname внутри объекта. Затем мы возвращаем объект.

Теперь в строке 16 мы вызываем функцию, а затем присваиваем возвращаемое значение, то есть объект в переменной person.
Переменная person может обращаться к getFirstName, но не к firstName. Это связано с тем, что область действия firstName находится со строки 2 по строку 13 и недоступна за ее пределами.

Но person.getFirstName () выполняется закрытие. Когда getFirstName был создан в строке 6, он получил снимок переменной firstName из-за концепции закрытия. Вот как person.getFirstName () может получить доступ к значению firstName.

На этом мы завершаем нашу серию статей о том, что вы не знаете, JS - области действия и замыкания. С сериями Объект и прототип вы можете ознакомиться здесь.