Hoisting happens on every execution context. During the hoisting variable or function declarations are not moving to the top, they are just being written to the memory.
When you run a javascript file, first global execution context is created. Global execution context gives global object, "this" keyword and hoists the var declarations and function declarations.
in the first part of your question:
var boo = 11
console.log(boo) // 11
var boo = 10
boo is hoisted like this:
var boo=undefined.
Because variables are PARTIALLY hoisted. var boo=10
is not going to overwrite var boo=undefined
. this is how it looks like after hoisting:
var boo=undefined
boo = 11
console.log(boo) // it is clear why 11
var boo = 10
in the second part of your question:
var boo = 11
function foo() {
console.log(boo)
var boo = 10
}
foo()
var boo in the global context is partially hoisted.
var boo=undefined
but this is not relevant to us. Because when we create a new function and invoke it, a new execution context is created and inside this execution context another hoisting takes place like this:
function foo() {
var boo=undefined
// "boo" is partially hoisted inside
// "boo" is written into the variable environment of the execution context
// "foo()" will always look into the its variable environment first
console.log(boo)
boo = 10
}
we defined a variable more than once but in different scopes. we have var boo =11
in parent scope and var boo=10
in the local scope. this is an example of variable shadowing. foo() will be using the local variable first, so local variable is shadowing over the parent's value.