Все просто. В замыкании и не замыкании нет разницы для интерпретатора - это не исключительная ситуация.
Нужно понять: замыкание это алгоритм, а не конструкция как например цикл или функция!!!
Функция createCounter() - возвращает анонимную функцию.
В анонимной функции используется переменная createCounter.
При просто вызове createCounter()(); :
createCounter() - инициализирует переменную (три раза) и возвратит анонимную функцию.
И три раза происходит вызов анонимной функции - вторые ().
После каждого из трех вызовов переменная numberOfCalls созданная при вызове createCounter уже не нужна.
Анонимная функция больше не будет использована в этом контексте.
В итоге функция и замкнутая переменная три раза попадают в уборщик мусора.
При Сохранении анонимной функции в переменную:Во-первых: numberOfCalls будет инициализирована только один раз, при записи fn = createCounter().
Где контекст анонимной функции записывается в переменную fn.
Во-вторых: так как контекст вызова сохранен, то замкнутая переменная и анонимная функция останутся лежать в нем.
В-третьих: при каждом вызове анонимной функции в сохраненном контексте переменная будет увеличиваться так как старое значение не инициализировано и не выброшено.
var fn = createCounter();
fn();
fn();
alert(fn()) // =3
fn = createCounter();
fn();
alert(fn()) // =2