Закрытие в JavaScript

Mar 18 2023
Что такое Closure и когда мы действительно можем его использовать? Чтобы понять Closure, нам нужно знать о двух простых концепциях в JavaScript: вложенные функции и возврат функции. Вложенные функции В JavaScript у нас могут быть вложенные функции.

Что такое Closure и когда мы действительно можем его использовать?

Чтобы понять Closure, нам нужно знать о двух простых концепциях в JavaScript: вложенные функции и возврат функции.

Вложенные функции

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

Давайте проверим следующий пример:

function greetPerson(name) {
  const message = 'Hello';
  
  function displayMessage() {
    console.log(`${message} ${name}!`);
  }

  displayMessage();
}

greetPerson('Alex'); // Hello Alex!

Возврат функции

Помимо объявления и вызова внутренней функции внутри внешней функции, мы также можем вернуть внутреннюю функцию, чтобы ее можно было вызывать извне.

Давайте посмотрим на пример этого:

function greetPerson(name) {
  const message = 'Hello';
  
  function displayMessage() {
    console.log(`${message} ${name}!`);
  }

  return displayMessage;
}

const displayMessageFunction = greetPerson('Alex');

console.log(typeof(displayMessageFunction)); // function
displayMessageFunction(); // Hello Alex!

Закрытие

После того, как мы поймем эти две концепции, «определение» замыкания станет довольно простым.

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

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

function counterFunction() {
 let counter = 0;

 function increaseCounter() {
  return counter += 1;
 }

 return increaseCounter;
}

// counter reffers to the increaseCounter returned by the counterFunction
const counter = counterFunction();

console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
console.log(counter()); // 4

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

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

Когда использовать замыкание?

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

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

const counter = (function () {
  let privateCounter = 0;

  function changeBy(val) {
    privateCounter += val;
  }

  function increaseCounter() {
    changeBy(1);
  }

  function decreaseCounter() {
    changeBy(-1);
  }

  function decreaseCounter() {
    return privateCounter;
  }

  return { increaseCounter, decreaseCounter, getCounterValue };
})();

console.log(counter.getCounterValue()); // 0

counter.increaseCounter();
counter.increaseCounter();

console.log(counter.getCounterValue()); // 2

counter.decreaseCounter();

console.log(counter.getCounterValue()); // 1

Мы можем управлять значением счетчика извне, только вызывая increaseCounterи decreaseCounter, и мы можем получить значение, вызывая getCounterValueфункцию, которая ведет себя как геттер.

Таким образом, мы можем смоделировать спецификаторы publicи privateдоступа и добиться инкапсуляции.

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

Вот и все!

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