Как происходит всплытие переменной?
Внутри функции наверх выплывает только объявление локальной переменной var foo;

var foo = 1; // можно стереть
function bar() { 
    var foo; // всплыло сюда. Этот foo – иной, чем верхний foo!
    if (!foo) { // тут foo undefined,  !foo === true
        foo = 10; // выполняется, назначается 10
    } 
    console.log(foo); // вывели 10
} 
bar(); //--> 10
Объявления переменных и функций всплывают на верх области видимости, у var и function (та что declaration) - это внешняя функция или модуль (если на верхнем уровне дело происходит), у let и const - блок, то есть после всплытия, внутри движка Ваш код будет выглядеть так:var foo; 
function bar() {
    var foo; // эта foo перекрывает foo из внешней области видимости, и поэтому в функции используется она
    if (!foo) { 
        foo = 10; 
    } 
    console.log(foo); 
}
foo = 1;
bar(); //--> 10

Так же важно знать, что хотя let и const всплывают наверх блока, но использовать их до фактического места объявления нельзя, так будет ошибка:{
    console.log(x); // ReferenceError: Cannot access 'x' before initialization
    let x;
}Это механизм защиты "от дурака" и называется он "мертвое всплытие". По этому всегда лучше использовать let или const, притом const предпочтительнее если переменная не меняется, так как дает больше гарантий.