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

Что такое Закрытие?

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

function MathOperation(operation) {
  if(operation === 'add'){
    return function(a, b){
        return a + b;
    }
  }else if(operation === 'subtract'){
    return function(a, b) {
      return x + y;
    };
 }
}

console.log(MathOperation('add')(5,3)); // 8
console.log(MathOperation('subtract')(5,3)); //2

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

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

Рассмотрим следующий пример с двумя анонимными функциями:

const add5 = function () {
  const x = 5;
  return function (y) {
    return x + y;
  };
}();

console.log(add5(3)); // 8
console.log(add5(4)); // 9
console.log(add5(15)); // 20

Здесь, когда вы объявляете const add5, у него есть выражение немедленно вызываемой функции (IIFE). Это означает, что функция, объявленная рядом с add5, следует за фигурными скобками (), что гарантирует выполнение функции немедленно во время объявления. В связи с этим после объявления add5 содержит определение функции, показанное ниже.

const add5 = function(y){
    return 5 + y;
 }

Обратите внимание, что здесь внутренняя функция несет контекст выполнения родительской функции в форме const x = 5;

Теперь, когда внешняя функция уже исчезла, нет другого способа изменить или получить доступ к значению x, кроме как через функцию add5. Эта техника называется замыканием.

Где я должен использовать замыкание?

Замыкания могут использоваться различными способами в реальном программировании на JavaScript. Некоторые распространенные варианты использования:

  1. Реализация закрытых переменных или методов. Вы можете использовать замыкание для создания закрытых переменных или методов, доступ к которым возможен только в пределах области замыкания.
function counter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
console.log(increment()); // 3

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

function person() {
  let name = "John Doe";
  return {
    getName: function() {
      return name;
    },
    setName: function(newName) {
      name = newName;
    }
  };
}

const john = person();
console.log(john.getName()); // John Doe
john.setName("Jane Doe");
console.log(john.getName()); // Jane Doe

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

function greeting(name) {
  return function(message) {
    console.log(`${message} ${name}`);
  };
}

const sayHi = greeting("John");
sayHi("Hello"); // Hello John

4. Реализация шаблонов модулей. Замыкания могут использоваться для создания модулей с закрытыми переменными и методами, доступ к которым извне невозможен. Это может быть полезно при создании автономных блоков кода.

function multiply(a, b) {
  return a * b;
}

function partialMultiplyByFive(b) {
  return multiply(5, b);
}

console.log(partialMultiplyByFive(2)); // 10
console.log(partialMultiplyByFive(3)); // 15

5. Обработчики событий. Замыкания могут использоваться для сохранения ссылки на конкретное состояние переменной даже после того, как произошло событие. Это может быть полезно при работе с обработчиками событий.

function addEventHandler(num1, num2) {
  return function() {
    console.log(num1 + num2);
  };
}

const btn = document.querySelector('button');
btn.addEventListener('click', addEventHandler(10, 20));

Заключение

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