[БЕЗ_ЗВУКА] Следующая тема, о которой мы поговорим, это замыкание. Существует несколько определений этого термина. Больше всего мне нравится следующее определение. Замыкание — это функция со всеми ее внешними переменными, к которым она имеет доступ. Давайте разберемся, как это работает. При объявлении новых переменных выделяется новый участок памяти. Чтобы разумно расходовать память, нужно вычищать из нее все переменные, которые больше никем не используются. Для этого в JavaScript используется такой механизм, как счетчик ссылок. Работает он следующим образом. Внутри функции greet на переменную text мы ссылаемся, то есть мы можем получить к ней доступ. Соответственно, счетчик ссылок не нулевой. Как только мы вышли за пределы функции greet, на переменную text больше никто не ссылается, то есть доступ к этой переменной мы не можем получить. Поэтому счетчик ссылок равен нулю. Все переменные, на которые никто не ссылается, сборщик мусора JavaScript может вычистить. Рассмотрим другой, чуть более сложный пример. Внутри функции makeCounter мы имеем доступ к переменной currentCount, поэтому счетчик ссылок на эту переменную не ноль. Однако и за пределами этой функции мы по-прежнему продолжаем ссылаться на эту переменную. Мы делаем это неявно через функцию Counter, которая имеет доступ к currentCount. В этом и есть смысл замыкания. Давайте посмотрим подробнее, как это работает. makeCounter в качестве результата возвращает новую функцию. Как вы уже знаете, в JavaScript область видимости создается функциями. При этом внутри этой функции мы обращаемся к переменной currentCount. Интерпретатор ведет себя следующим образом. Ищем currentCount в текущей области видимости, в области видимости функции, которую возвращаем. Не находим ничего и идем в родительскую функцию. Там объявлена переменная currentCount, к ней мы имеем доступ. Таким образом, вызываю функцию Counter, мы будем увеличивать счетчик внешней переменной на 1. Однако если мы позовем функцию makeCounter еще раз, мы получим новую функцию, которая ссылается уже на новую переменную currentCount вне зависимости от первой переменной. Давайте рассмотрим еще один пример замыкания. Объявим функцию greet, которая принимает переменную name и так же, как в предыдущем примере, возвращает новую функцию. Поскольку переменная name является внешней по отношению к этой функции, также является замыканием. Вызывая функцию greet с некоторой строкой, например, строкой ('мир!'), мы получаем новую функцию helloWorld, вызывая которую, к нам возвращается строка "Привет, мир!" Возможно, вы уже использовали замыкание, когда писали свой код, просто не задумывались об этом. Использование внешних по отношению к функции переменных — достаточно естественный процесс, и по ходу курса мы будем часто возвращаться к теме замыкания. Сейчас мы рассмотрим практический пример использования замыкания для создания модуля. Определим в нашем коде две функции. Функцию format, которая преобразует переданную дату в строку. И функцию getDateString, которая определяет Date, если не определено текущим временем, и возвращает время в виде строки. Если мы вызовем getDateString, не передав туда аргументы, мы получим текущую дату в виде строчки. Если код нашего проекта достаточно большой, то мы сами или наш коллега может переопределить поведение функции format случайно. При этом поведение функции getDateString будет испорчено. Вместо того чтобы возвращать текущую дату в виде строки, она будет возвращать новую строку, определенную в новой функции format. Чтобы защитить поведение функции getDateString, мы сможем воспользоваться pattern module. Для того чтобы определить модуль, мы воспользуемся самовызывающейся функцией. Перепишем наш исходный код следующим образом. Функцию format и getDateString мы обернем в новую функцию, которую сразу же и вызовем. Из этой функции мы будем возвращать функцию getDateString и складывать в переменную с одноименным названием. Для того чтобы показать, что это самовызывающаяся функция, я оставил до ключевого слова function открывающуюся скобочку. В данном случае это было делать не обязательно, но я настоятельно рекомендую вам ставить открывающуюся круглую скобочку, чтобы программисту, который читает ваш код, было понятно, что вы не просто объявляете новую функцию, а вы объявляете функцию, которая будет непосредственно вызвана. Поскольку функция format и getDateString находятся внутри новой самовызывающейся функции, то есть портить их значения нельзя. Об этом мы говорили, когда касались темы затенения. Для того чтобы написать самовызывающуюся функцию, мы должны определить ее в режим function expression. Для того чтобы интерпретатор отличил это от function declaration, мы ставим открывающуюся круглую скобочку до ключевого слова function. Закрывающуюся круглую скобочку мы можем поставить как после вызова самовызывающейся функции, так и до ее вызова. Оба этих способа являются правильными, и вы можете их использовать. Кроме того, в режим function expression мы можем перейти, если поставим до ключевого слова function восклицательный знак или знак плюс. Однако такой код встречается редко, и я не советую вам его использовать. С использованием самовызывающихся функций мы можем реализовать pattern module. В этой неделе мы поговорили с вами о том, как можно работать с аргументами, о том, как присваивать значение по умолчанию непереданным аргументам, как работать с объектом arguments. Мы поговорили про несколько способов объявления функций, о таких понятиях, как всплытие переменных и функции и замыкание. С использование замыкания и самовызывающейся функции реализовали pattern module.