1. Введение

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

Лексическая область видимости:

Возможность области функции получать доступ к переменным из родительской области называется лексической областью. Мы называем лексическую привязку родительской функции к дочерней функции «лексической привязкой».

2. Давайте посмотрим и поймем замыкание на примере:

2.1 Пример 1: В этом примере показано основное использование замыкания.

function init() {
  var name = "Closure"; // name is a local variable created by init
  function displayName() {
    // displayName() is the inner function, that forms the closure
    console.log(name); // use variable declared in the parent function
  }
  displayName();
}
init();

init() создает локальную переменную с именем name и функцию с именем displayName(). Функция displayName() — это внутренняя функция, определенная внутри init() и доступная только внутри тела функции init(). Обратите внимание, что функция displayName() не имеет собственных локальных переменных. Однако, поскольку внутренние функции имеют доступ к переменным внешних функций, displayName() может получить доступ к переменной name, объявленной в родительской функции init().

3. Определение области действия с помощью let и const :

Традиционно (до ES6) в JavaScript было только два типа областей: область действия и глобальная область действия. Переменные, объявленные с помощью var, относятся либо к функции, либо к глобальной области, в зависимости от того, объявлены ли они внутри функции или вне функции. Это может быть сложно, поскольку блоки с фигурными скобками не создают области видимости:

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);

Для людей, говорящих на других языках (например, C, Java), где блоки создают области видимости, приведенный выше код должен выдавать ошибку в строке console.log, поскольку мы находимся за пределами области действия x ни в одном блоке. Однако, поскольку блоки не создают области видимости для var, операторы var здесь фактически создают глобальную переменную. Ниже также представлен практический пример, который иллюстрирует, как это может вызвать реальные ошибки в сочетании с замыканиями.

В ES6 в JavaScript появились объявления let и const, которые, помимо прочего, например временных мертвых зон, позволяют создавать переменные с областью действия блока.

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined

По сути, блоки в ES6 наконец-то рассматриваются как области видимости, но только если вы объявляете переменные с let или const. Кроме того, в ES6 появились модули, которые представили еще один тип области видимости. Замыкания могут захватывать переменные во всех этих областях, о которых мы расскажем позже.

4. Закрытие:

function makeFunc() {
  const name = "closure";
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();

Выполнение этого кода имеет тот же эффект, что и предыдущий пример функции init() выше. Отличием (и интересным) является то, что внутренняя функция displayName() возвращается из внешней функции перед выполнением.

На первый взгляд может показаться неочевидным, что этот код все еще работает. В некоторых языках программирования локальные переменные внутри функции существуют только на время выполнения этой функции. Как только makeFunc() завершит выполнение, вы можете ожидать, что переменная name больше не будет доступна. Однако, поскольку код по-прежнему работает должным образом, в JavaScript это явно не так.

Причина в том, что функции в JavaScript образуют замыкания. Замыкание — это комбинация функции и лексического окружения, в котором эта функция была объявлена.

Эта среда состоит из любых локальных переменных, которые находились в области видимости на момент создания замыкания. В данном случае myFunc является ссылкой на экземпляр функции displayName, который создается при запуске makeFunc. Экземпляр displayName сохраняет ссылку на свое лексическое окружение, в котором существует переменная name. По этой причине при вызове myFunc переменная name остается доступной для использования, а «закрытие» передается в console.log.

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

Ребенок(внутренняя функция)может брать мороженое у старших(внешние функции)но старшие не могут брать мороженое у детей