Я пытаюсь понять закрытие в Javascript. Я наткнулся на этот пример:
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
add();
add();
add();
Я не понимаю, почему значение счетчика становится равным 3. Я ясно вижу, что счетчик инициализируется 0 каждый раз, когда вызывается функция.
Я хочу знать, как обстоят дела под капотом. Как работает движок JavaScript? Не могли бы вы сослаться на более подробный пример или статью.
Давайте посмотрим, что и в каком порядке интерпретируется.
Шаг №1:
В var add = (something)()
первое, что нужно оценить, это «что-то».
Шаг № 2:
После того, как функция оценена как допустимая, на нее есть ссылка, которая еще не сохранена в переменной и никогда не будет сохранена, потому что функция выполняется сразу же из-за второго набора скобок.
Шаг №3:
Эта функция делает две вещи:
1) присваивает 0
переменной counter
.
2) объявляет другую функцию: function () {counter += 1; return counter}
. Ссылка на эту функцию будет присвоена переменной add
.
Шаг № 4:
Итак, каждый раз, когда вызывается add()
, выполняется counter += 1; return counter
.
Объем:
Переменная counter
существует только во внешней и внутренней функциях. Внешняя функция никогда не сохраняла свою ссылку в переменной, потому что она была вызвана немедленно, поэтому она никогда не будет вызываться снова. Ссылка на внутреннюю функцию была сохранена в add
и может быть вызвана снова.
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
// Notice that add is the "inner" function
console.info(add)
// What is returned by add is the counter value
var firstCall = add();
var secondCall = add();
var thirdCall = add();
console.info(firstCall, secondCall, thirdCall)
// the counter does not exist outside the scope of the inner function
console.info(typeof(counter))
Хорошей ссылкой, которую я могу предложить, чтобы узнать больше о том, как интерпретируется JS, является Wakata.io ... В частности, раздел CompuThink по вашему вопросу.
Функция в круглых скобках, за которой следует еще одна пара круглых скобок, представляет собой IIFE — немедленно вызываемое функциональное выражение.
//immediately invoked function expression
(function() {
var counter = 0;
return function() {
counter += 1;
return counter;
}
})();
Это называется так, потому что эта функция вызывается сразу после ее определения.
Переменной add не назначается IIFE. Скорее, он получает результат вызванной функции, как показано ниже.
function() {
counter += 1;
return counter;
}
Замыкание — это средство, с помощью которого функция получает доступ к области, в которой она создана.
Эта функция имеет доступ к переменной счетчика в IIFE из-за поведения закрытия. Несмотря на то, что время жизни IIFE уже закончилось, функция добавления переменной имеет к нему доступ из-за закрытия.
Всякий раз, когда мы вызываем add(), он фактически обновляет счетчик в IIFE. Все это время IIFE больше никогда не выполнялся. Он запускался только один раз на начальном этапе.
Вы вызываете внутреннюю функцию несколько раз, а не внешнюю. Немедленно вызывается внешняя функция, которая устанавливает
counter = 0
иadd
внутреннюю функцию, которая возвращается.