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

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

Чтобы понять, как работают замыкания, давайте начнем с основ цепочки областей видимости в JavaScript.

В JavaScript каждая функция имеет свою область видимости, и переменные, объявленные внутри функции, не видны за ее пределами.

Однако функции могут обращаться к переменным, объявленным в своих родительских функциях, вплоть до глобальной области видимости.

Вот пример:

function outer() {
  const a = 1;
  function inner() {
    const b = 2;
    console.log(a + b); // Output: 3
  }
  inner();
}
outer();

В этом примере функция inner может получить доступ к переменной a, объявленной в функции outer, благодаря цепочке областей видимости. Однако после завершения выполнения функции outer переменная a становится недоступной.

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

function outer() {
  const a = 1;
  function inner() {
    const b = 2;
    console.log(a + b); // Output: 3
  }
  return inner;
}
const closure = outer();
closure(); // Output: 3

В этом примере функция outer возвращает функцию inner, которая затем присваивается переменной closure. Когда мы вызываем closure(), функция inner выполняется и все еще может получить доступ к переменной a, объявленной в функции outer, даже если функция outer уже завершила выполнение.

Замыкания полезны во многих сценариях, таких как создание закрытых переменных и методов, реализация каррирования и частичного применения, а также реализация обработчиков событий и обратных вызовов.

Вот пример того, как замыкания можно использовать для создания приватных переменных и методов:

function counter() {
  let count = 0;
  function increment() {
    count++;
    console.log(count);
  }
  function decrement() {
    count--;
    console.log(count);
  }
  return {
    increment,
    decrement,
  };
}
const myCounter = counter();
myCounter.increment(); // Output: 1
myCounter.increment(); // Output: 2
myCounter.decrement(); // Output: 1

В этом примере функция counter возвращает объект с двумя методами, increment и decrement, которые имеют доступ к переменной count, объявленной в функции counter. Переменная count недоступна за пределами функции counter, что фактически делает ее частной.