Annotated source; I'm assuming this code starts out at global scope:
var local = true; // Creates a global variable called `local`
function outer() {
/* local scope */
var local = false; // Creates a local `local` within `outer`, shadowing (hiding) the global
function inner() {
alert(local); // alerts "undefined", the value of `inner`'s `local`
var local; // Creates a local `local` within `inner`, shadowing (hiding) `outer`'s version
}
inner();
}
outer();
function a(x) { // Creates a global function `a`
return x * 2;
}
var a; // Has no effect
alert(a); // alerts the function source (on engines that have it)
There are basically three things at work in the code above:
A declaration in a nested scope shadows (hides) a declaration in a containing scope. So the local
in outer
shadows the global, and the local
in inner
shadows outer
's local
.
var
declarations are processed when execution enters an execution context, not where they appear in the source code. They're sometimes said to be "hoisted" because they are effectively moved up (raised, hoisted) to the top of the context in which they occur. (More: Poor misunderstood var
) This effect is particularly noticeable within the inner
function, because the local
being alerted is the one from inner
, not the one from outer
(which is why it's undefined
), even though the declaration is underneath the alert.
Function declarations create a symbol in the scope in which they're defined, in the same symbol space as var
declarations do. (Specifically, they both create entries in the binding object of the lexical environment of the execution context in which they occur.) So if you have a function declaration and a var
with the same name (as you do with a
at the end of your code), there's a conflict. Which wins? The function declaration wins, because of the order dictated by §10.5 of the specification, which says that function declarations occur before var
declarations, and that a var
for a symbol that's already defined doesn't override it.