В общем, вероятно здесь действительно дело в hoisting, и
Дмитрий Беляев прав. Немного по-экспериментировал, и сделал такой вывод(если ошибаюсь поправьте).
При начале чтения блока с кодом, Js осуществляет hoisting декларативных функций и объявлений переменных в рамках видимости читаемого блока, не затрагивая сразу изолированные подблоки, которые есть в коде. Далее, когда Js добирается до подблока, опять происходит hoisting в рамках данного подблока для переменных, а декларативная функция всплывает в глобальную область видимости. Причем похоже,что процесс всплытия для функции происходит дважды. Например для:
{
//произошло всплытие b = ƒ b() { } в глобальную область сразу
1. function b() { }; // повторно вынесло b = ƒ b() { } в глобальную область
2. b = 'foo'; // переназначено значение переменной b = 'foo' в рамках данной области
3. let any;
}
4. console.log(b); // как результат ƒ b() { }
И второй случай:
{
//произошло всплытие b = ƒ b() { } в глобальную область сразу
1. b = 'foo'; // переназначено значение переменной b = 'foo' в рамках данной области
2. function b() { }; // повторно вынесло b в глобальную область, но значение для b уже было b = 'foo'
3. let any;
}
4. console.log(b); // как результат b = 'foo'
Хз, вроде подогнал логику под свои эксперименты. И все же не совсем правильно у меня описано скорее всего. "Повторный вынос" декларативной функции вряд ли можно назвать всплытием. Может и вообще всё по-другому объясняется. Но работает по факту так :/