Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

Возврат функции из функции - как работает замыкание? [дубликат]



    На данный вопрос уже ответили:
    
        
            Как работают замыкания в JavaScript
                
                    7 ответов
                
        
    
    
Учу js и, к сожалению, не понял одну вещь

function makeCounter() {
  var currentCount = 1;

  return function() { // (**)
    return currentCount++;
  };
}

var counter = makeCounter(); // (*)

// каждый вызов увеличивает счётчик и возвращает результат
alert( counter() ); // 1
alert( counter() ); // 2
alert( counter() ); // 3

// создать другой счётчик, он будет независим от первого
var counter2 = makeCounter();
alert( counter2() ); // 1


Вопрос 1: почему при первом вызове функции переменная currentCount = 1, ведь возвращаемое функцией currentCount++, следовательно должно быть 2. Так почему 

return function()...


пропускается?

Вопрос 2: почему при вызовах функции currentCount не присваивается 1, ведь

var currentCount = 1;

    


Ответы

Ответ 1



Когда в строке var counter = makeCounter(); выполняется функция makeCounter, он присваивает значение 1 своей локальной переменной currentCount и возвращает, но не выполняе анонимную функцию. Так как анонимная функция использует переменную из внешней области видимости, создается "замыкание" (closure), которое соединяет экземпляр переменной currentCount с возвращаемым экземпляром анонимной функции.

Ответ 2



Попробую объяснить на пальцах. Данная строка кода var counter = makeCounter(); // (*) Делает примерно следующее var currentCount = 1; var counter = function() { // (**) return currentCount++; }; Только переменная currentCount не глобальная, а находится в "замыкании", то ест видна исключительно внутри функции. Собственно makeCounter() больше уже не выполняется никогда при вызове counter(), тут сама переменная counter является функцией, которая имеет исключительный доступ к переменной currentCount. Вся идея создания функции counter() не напрямую через присваивание, а через другу функцию makeCounter() заключается как раз в том, чтобы привязать к ней переменную, котору видит исключительно counter() и которая сохраняет свое значение между вызовами. В других языках программирования существуют так называемые статические переменные - их смысл как раз в том, чтобы сохранять значение между вызовами функции, но при этом быть доступными только внутри функции. Механим создания замыкания примерно такой. Когда вызывается функция для всех ее локальны переменных выделяется область памяти. Когда функция заканчивает свою работу, то эт область памяти очищается - в этом смысл локальных переменных, они живут, пока исполняетс функция. Однако если внутри функции (у вас это makeCounter()) объявить другую функци (которая тоже будет как бы локальной переменной-функцией), а потом вернуть объявленну функцию (она у вас анонимная, но назовем ее counter(), по имени переменной в которо она сохранится) вызывающему коду, то область памяти с локальными переменными будет "жить" до тех пор, пока возвращенная функция "живет" в переменной во внешнем коде. При этом к этой области памяти доступ будет иметь только, возвращенная функция. Возвращенная функция и связанная с ней область памяти называется замыканием. Если вызвать makeCounter() повторно, то выделиться новая область памяти, объявится и вернется новая функция, образуется новое замыкание - поэтому counter'ы независимы друг от друга, так как "смотрят" в разные области памяти и "видят" там разные переменные currentCount'ы Что касается постфикного (currentCount++) и префиксного (++currentCount) инкремента, то @PeterOslon хорошо объяснил.

Ответ 3



Есть разница между префиксный инкремент ++x и постфиксный инкремент x++. x++ - это возвращает значение x, потом добавляет 1 к x. ++x - добавляет 1 к x, потом возвращает значение x. Так что return function() { return currentCount++; }; вырабатывается примерно так: return function() { var temp = currentCount; currentCount = currentCount + 1; return temp; };

Комментариев нет:

Отправить комментарий