Разбираем задачу про hoisting и лексическое окружение в JavaScript

Область видимости — определяет, где доступны переменные и функции (в пределах блоков кода { }, функций или глобально).
В задаче 2 области видимости: глобальная и локальная (внутри функции showNum)
Лексическое окружение — определяет, как и где переменные и функции доступны в коде. Хранит переменные и функции локальной области видимости и ссылку на внешнее окружение.
У функции showNum есть локально объявленная переменная num и ссылка на родительское окружение (где тоже есть переменная num, к которой обращаться нет необходимости — поиск переменной во внешнем окружении происходит только при отсутствии такой локальной).
А как функция узнала о локальной num, если она объявлена не сразу?
В JavaScript, объявления переменных «поднимаются/всплывают» вверх своей области видимости ещё до начала выполнения кода. Это называется hoisting (поднятие/всплытие). Переменные, объявленные при помощи ключевых слов let и const остаются неинициализированными (в отличие от var, которые инициализируются значением undefined).
Инициализация переменной — присваивание начального значения переменной в момент объявления.
Когда в 4 строке пытаемся вывести num в консоль, возникает исключение ReferenceError. Функция уже знает о локальной num, которая остается непроинициализированной до 6 строки — попали во «временную мертвую зону».
Temporal Dead Zone (TDZ) — это период времени между объявлением переменной и инициализацией значением, в течение которого к переменной нельзя получить доступ (касается только переменных, объявленных при помощи let и const).
Здесь выполнение функции прерывается, и, так как исключение никак не обработали, дальше код выполняться не будет.
Зачем это нужно
Наличие «мертвой зоны» помогает писать последовательный и предсказуемый код — это уменьшает вероятность ошибок и улучшает читаемость кода.