This is an analysis of what's happening with a debugger in Node.js. It doesn't explain why this is happening.
There are 3 scopes involved: local scope, global scope and block scope.
I did the same analysis in a Chrome browser. The behavior was similar with the only difference that there is no local scope and instead of the local scope the global scope was used.
The code
{
    foo = 1;
    foo = 2;
    console.log(foo);
}
console.log(foo);
 
 
creates a variable in global scope and sets two different values for that variable. In this code
{
    function foo() { }
    foo = 1;
    foo = 2;
    console.log(foo);
}
console.log(foo);
 
 
the line function foo() { } creates a variable foo in block scope and a variable foo in local scope (global scope in Chrome). Since there exists a variable in block scope foo = 1; sets a value for the existing variable in block scope and doesn't create a variable in global scope. foo = 2; sets a different value for the same variable. The first console.log(foo); prints 2 from block scope and the second console.log(foo); prints f foo() { } from local scope (global scope in Chrome).
In this code
{
    foo = 1;
    function foo() { }
    foo = 2;
    console.log(foo);
}
console.log(foo);
 
 
the function declaration function foo() { } is hoisted and creates a variable foo in block scope with value f foo() {} and a variable foo in local scope (global scope in Chrome) with value undefined. The line foo = 1; sets both variables to 1. The line foo = 2; sets the variable in block scope to 2. The first console.log(foo); prints 2 from block scope and the second console.log(foo); prints 1 from local scope (global scope in Chrome).
In this code
{
    function foo() { }
    foo = 1;
    function foo() { }
    foo = 2;
    console.log(foo);
}
console.log(foo);
 
 
the function declaration function foo() { } creates a variable foo in block scope with value f foo() {} and a variable foo in local scope (global scope in Chrome) with value f foo() {}. The line foo = 1; sets both variables to 1. The line foo = 2; sets the variable in block scope to 2. The first console.log(foo); prints 2 from block scope and the second console.log(foo); prints 1 from local scope (global scope in Chrome).