Note:Below description is as of ES5, NOT ES6 since in ES6 scoping rules have been changed(due to introduction of let).
Javascript does compile. It's just that like other languages such as c++/c# there is NO intermediate thing like exe/IL code that need to be clicked to start execution. In JS execution starts after compile phase.
So, when the compilation happens the compiler looks for function declaration and var declaration
for variables. Therefore for this IIFE,
(function () {
var x = 42;
show();
})();
It does find one var declaration and the variable x is registered in the scope of the IIFE. This is called variable hoisting and x is available at the function level, in this case IIFE.
Later at execution time, the IIFE looks like this(conceptually):
(function () {
//registration of x in this function's scope has already happened at
//compile time. Notice absence of `var`
x = 42;
show();
})();
Now, at this time the engine talks to scope and asks for lvalue reference of x. Since x was registered in IIFE, engine gets one and then 42 is assigned to it.
Now for this part:
function show() { console.log(x); }
When show is called, engine first asks scope of show function for x, since it doesn't have any variable registered with the name x, global scope is asked( rvalue reference) for x, since it was never registered with global scope either during compilation phase, it cannot be found in any of the scope and we get reference error.
it should know that x == 42 at the time it calls show(), which is inside the anonymous function, correct?
Because of scoping rules, variables in outer scopes are visible in inner scope but not vice-versa. x
inside IIFE is visible at the IIFE level and not outside in outer scope.