Все, что вам нужно знать о замыканиях (основная часть Javascript, часть 2)

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

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



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

достаточно предыстории, давайте начнем с замыканий:

Из MDN определение закрытия:

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

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

для например. пример взят из MDN.

function makeFunc() {
  var name = 'Mozilla';
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

Давайте разберемся с приведенным выше кодом. ссылка makeFunc хранится в переменной с именем myFunc, и затем мы можем использовать ссылку для вызова функции позже, то есть myFunc(). в первый раз, когда вызывается makeFunc, JS создаст свой собственный контекст выполнения, где имя инициализируется с помощью «Mozilla», а внутри makeFunc есть еще одна функция, называемая displayName, которая возвращается позже.

Теперь displayname создаст свой собственный контекст выполнения, и весь контекст будет храниться в стеке выполнения (способ FIFO). при первом вызове функция displayName не будет вызываться, только будет создан ее контекст.

Наконец, когда мы выполним последнюю строку, будет выполнено displayName, где будет выполнено предупреждение (имя). Но подождите, как displayName получает имя значения? имя объявляется во внешней функции, а переменная с именем name не объявляется внутри displayName. то как эта внутренняя функция получит переменную имени. это магия замыканий!!!

Примечание. Лексическая область видимости. Эта область видимости позволяет внутренней функции обращаться к переменной, объявленной вне этой функции.

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

Теперь давайте вернемся к первому заданному вопросу. Что будет на выходе? Как это будет выполняться?

он будет выполнен с помощью замыканий. когда пользователи нажимают, этот EventListener будет вызываться и создавать переменную с именем clear. теперь будет выполняться внутренняя функция, в которой мы очищаем тайм-аут, созданный setTimeout, на 2 секунды. через 2 секунды консоль запустится и напечатает hit api. Но что произойдет, если пользователь снова щелкнет, он просто снова пройдет процесс и распечатает вывод. Но что, если пользователь щелкнет в течение 2 секунд, будет ли он консолью? ответ - нет. Зачем?

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

Заключение

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