Переменные в IIFE

Я пытаюсь понять закрытие в Javascript. Я наткнулся на этот пример:

var add = (function () {
  var counter = 0;
  return function () {counter += 1; return counter}
})();

add();
add();
add(); 

Я не понимаю, почему значение счетчика становится равным 3. Я ясно вижу, что счетчик инициализируется 0 каждый раз, когда вызывается функция.

Вы вызываете внутреннюю функцию несколько раз, а не внешнюю. Немедленно вызывается внешняя функция, которая устанавливает counter = 0 и add внутреннюю функцию, которая возвращается.

Nick Parsons 13.12.2020 07:57

Я хочу знать, как обстоят дела под капотом. Как работает движок JavaScript? Не могли бы вы сослаться на более подробный пример или статью.

user13963926 13.12.2020 08:02
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
349
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Давайте посмотрим, что и в каком порядке интерпретируется.

  • Шаг №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 больше никогда не выполнялся. Он запускался только один раз на начальном этапе.

Другие вопросы по теме

Как написать лениво оцениваемый двойной цикл for в функциональном стиле?
Добавление встроенных аннотаций явного типа к замыканию с возвращаемым значением, но без входных параметров в Swift?
Каков правильный тип возвращаемого значения функции, возвращающей итератор, созданный с замыканием, заимствующим себя
Не может выйти из захваченной переменной в асинхронном закрытии `Fn`
Могу ли я написать код ржавчины, эквивалентный приведенному ниже машинописному коду?
Как получить доступ к переменной в Rust после того, как она была перемещена в замыкание с помощью ключевого слова «переместить»?
Откуда берется дополнительный параметр в скомпилированной лямбда-функции?
Может кто-нибудь объяснить, что означает «дополнительное конечное закрытие, переданное при вызове»?
Почему Rust применяет «статическое время жизни», даже если я его указал? Могу ли я переопределить это?
Можете ли вы объяснить мне код JS? Как это работает?