#javascript #замыкания
На этот вопрос уже даны ответы здесь: Как работают замыкания в JavaScript (7 ответов) Закрыт 3 года назад. Что такое замыкания мне понятно, но в ходе их исследования возникли нюансы: Есть код: Не могу осознать благодаря чему переменная numberOfCalls в функции createCounter не обнуляется? Это фишка такая или этому есть разумное объяснение?
Ответы
Ответ 1
"Вы вызываете один раз функцию createCounter". "Замыкание" - создание объекта, содержащего экземпляры всех переменных из внешних областей видимости, используемых функцией. Вызовите функцию еще раз , а потом начинайте вызывать два результата в произвольном порядке: $(document).ready(function() { function createCounter() { var numberOfCalls = 0; return function() { return ++numberOfCalls; }; } function appendOutput(aText) { $("#output").append(aText + "
"); } $("#btnRun").click(function() { $("#output").html(""); var fn1 = createCounter(); var fn2 = createCounter(); appendOutput("fn1: " + fn1()); appendOutput("fn1: " + fn1()); appendOutput("fn1: " + fn1()); appendOutput("fn2: " + fn2()); appendOutput("fn2: " + fn2()); appendOutput("fn1: " + fn1()); }); });outputОтвет 2
Её [переменную] один раз инициализировали, возвращённая функция находится вложеннее, и, так как переменная используется в функции, сборщик не убирает её. Полезное чтение почему так происходит.Ответ 3
Особенность вложенных функций состоит в том, чтобы получать значения из нее. В данном случае, внутри одной функции создаётся другая и возвращается в качестве результата. В разработке интерфейсов это совершенно стандартный приём, функция затем может назначаться как обработчик действий посетителя. function createCounter() { // LexicalEnvironment = { numberOfCalls: undefined } var numberOfCalls = 0; // LexicalEnvironment = { numberOfCalls : 0 } return function() { // [[Scope]] -> LexicalEnvironment (**) return numberOfCalls++; }; } Как видно, мы получили независимый счётчик function(), каждый из которых, незаметным снаружи образом, сохраняет текущее количество вызовов. Если подробнее описать происходящее: 1) В строке (*) запускается createCounter(). При этом создаётся LexicalEnvironment для переменных текущего вызова. В функции есть одна переменная var numberOfCalls, которая станет свойством этого объекта. Она изначально инициализируется в undefined, затем в процессе выполнения получит значение 0. 2) В процессе выполнения createCounter() создаёт функцию в строке (**). При создании эта функция получает внутреннее свойство [[Scope]] со ссылкой на текущий LexicalEnvironment. 3) Далее вызов createCounter() завершается.
Комментариев нет:
Отправить комментарий