Замыкания — одна из самых мощных функций языка программирования JavaScript. Они предоставляют способ создания «приватных» переменных и функций внутри функции, доступ к которым может получить только внутренняя функция. Это создает область, которую можно использовать для сохранения состояния функции даже после ее возврата.

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

function outerFunction() {
  let x = 10;

  function innerFunction() {
    console.log(x);
  }

  return innerFunction;
}

const closure = outerFunction();
closure(); // outputs: 10

В этом примере outerFunction возвращает innerFunction. При вызове closure в журнал записывается значение x, равное 10. Хотя x определено в outerFunction, оно доступно из innerFunction, поскольку innerFunction имеет доступ к области действия outerFunction. Это называется областью закрытия и создается при определении функции.

Замыкания также можно использовать для создания «приватных» переменных и функций, доступ к которым может получить только внутренняя функция:

function counter() {
  let count = 0;

  function increment() {
    count++;
    console.log(count);
  }

  return increment;
}

const myCounter = counter();
myCounter(); // outputs: 1
myCounter(); // outputs: 2

В этом примере counter возвращает increment, у которого есть доступ к закрытой переменной count. Это означает, что count может быть доступен и изменен только increment и недоступен из-за пределов функции counter.

Замыкания также можно использовать для сохранения состояния функции даже после ее возврата:

function add(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = add(5);
console.log(add5(3)); // outputs: 8

В этом примере add возвращает функцию, которая принимает один аргумент y и добавляет его к x. Когда вызывается add5, он возвращает функцию, которая добавляет 5 к своему аргументу. Это означает, что состояние x сохраняется даже после возврата функции add.

Сложный пример:

function outerFunction(x) {
  return function innerFunction(y) {
    return function innermostFunction(z) {
      return x + y + z;
    };
  };
}

const add5 = outerFunction(5);
const add5and10 = add5(10);
console.log(add5and10(3)); // outputs: 18

В этом примере outerFunction принимает аргумент x и возвращает функцию innerFunction. innerFunction принимает аргумент y и возвращает другую функцию innermostFunction. innermostFunction принимает аргумент z и возвращает сумму x, y и z.

Переменной add5 присваивается результат вызова outerFunction с аргументом 5. Переменной add5and10 присваивается результат вызова add5 с аргументом 10. Наконец, add5and10 вызывается с аргументом 3, который возвращает сумму 5, 10 и 3, что равно 18.

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

В этом примере также показано, как можно использовать замыкания для создания и сохранения состояния даже после возврата родительской функции. Самая внутренняя функция имеет доступ к переменным x, y и z, даже если они определены в родительских функциях. Это означает, что состояние переменных сохраняется даже после возврата самой внешней функции.

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