Если вы слышите слово "замыкание" впервые, оно может заставить вас нервничать. Но не стоит волноваться. На самом деле, замыкание - это просто. Для того, чтобы понять, как работает замыкание, необходимо вспомнить, что является областью видимости в Javascript. Вопрос с подвохом, так как для ключевого слова var
это строго функция, а для let
- любой функциональный блок. Для примера используем var
, которая используется внутри какой-либо функции:
function iterator() {
var counter = 0;
}
Как мы знаем, переменная, объявленная внутри определенной области видимости, не будет доступна извне. В случае, если такая переменная уже существует в родительской области видимости, она будет переобъявлена. Что же касается всех последующих дочерних областей видимости, переменная counter
в них будет доступна. К примеру, давайте внутри нашей функциии iterator
мы собъявляем в качестве возвращаемого значения другую функцию:
function iterator() {
var counter = 0;
return function increment() {
return ++counter;
}
}
Обратите внимание, что переменная counter
не была переобъявлена, но была переиспользована. Внутри функции increment
мы пользуемся поступностью переменной, объявленой в более высокой области видимости. И самое интересное: давайте воспользуемся написанным выше кодом:
var counterValue;
var increment = iterator();
counterValue = increment(); // 1
counterValue = increment(); // 2
counterValue = increment(); // 3
В результате вызова функции iterator()
, нам предоставилась возможность использовать функцию increment()
в другой области видимости. При этом, оригинальная функция iterator()
продолжила иметь доступ к переменной counter
в области видимости, где она была объявлена.
Ситуация, в которой функция может использовать переменные области видимости, внутри которой она была объявлена, и называется замыканием.
Для того, чтобы сделать наш модуль переиспользуемым, давайте его модифцируем:
function iterator(initialValue) {
var counter = initialValue || 0;
return {
inc: function() { counter++; },
dec: function() { counter--; },
val: function() { return counter; },
reset: function() { counter = 0; }
}
}
Благодаря данной модификации, будет возможно уменьшать и даже сбрасывать счетчик, причем каждая из трех объявленных функций будет иметь доступ к переменной counter
.
var counterValue;
var iterate = iterator(4); // Устанавливаем начальное значение счетчика
iterate.inc(); // 5
iterate.dec(); // 4
iterate.reset(); // 0
iterate.inc(); // 1
console.log(iterate.val());