Рассмотрим на примере v8, хотя все js движки с jit компиляцией (все современные) работают похожим образом.
В движок передан некий js код, он разбирает код в ast дерево компилирует верхний уровень и запускает его в указанном контексте (глобальный объект), все функции объявленные на 1м уровне в этот момент существуют просто как кусок ast дерева.
При первом запуске любой функции, v8 компилирует ее дерево по аналогичным правилам + работает оптимизатор, который анализирует выполнение и перестраивает ast-дерево для более быстрой его работы. Именно поэтому первый запуск любой функции всегда медленнее чем последующие.
Если оптимизатор успешно отработал и дерево было изменено - функция перекомпилируется. Но тут важно первое условие, если в функции присутствуют конструкции которые нельзя оптимизировать из-за их непредсказуемости, то оптимизатор не работает.
Теперь к примеру автора вопроса.
У нас есть замыкание, в котором func1 при каждом своем запуске создает новую версию func2. Если оптимизация func1 прошла успешно, то компилированный код func2 будет вшит в func1, то есть не смотря на то что при каждом вызове func1 мы имеем дело с новой func2, компилироваться все будет 1 раз (точнее 2, так как оптимизатор перекомпилирует).