Good question. Let's see what's going on:
dummy()
is a Function Call (11.2.3)
See step #8 "Return the result of calling the [[Call]] internal method on func, providing thisValue as the this value and providing the list argList as the argument values."
So dummy.[[Call]]
is invoked. Moving onto 13.2.1 ([[Call]]
).
Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.
So dummy()
does in fact create new execution context as described in 10.4.3.
Now that dummy
's function code is executed, NewDeclarativeEnvironment is created as per step #5 in 10.4.3 passing dummy.[[Scope]]
dummy
is just a reference to bar
, so dummy.[[Scope]]
is bar.[[Scope]]
. And bar.[[Scope]]
was defined at the moment when foo
executed (a line earlier), naturally creating functions for each function declaration within (including bar
).
bar.[[Scope]]
is essentially a chain consisting of [global environment]
and [foo VE]
(Variable Environment). So at the moment of its execution it creates its own VE and uses foo's VE as the outer. Scope chain now consists of [global environment]->[foo VE]->[bar VE]
.
x
is found in var's VE, y
is found in bar's VE, and alert successfully receives 3
as an argument :)
But to answer your original question, yes "entering function code" happens in case of
(function(){ ... })();
and in case of
f();
since both of them essentially call function's [[Call]]. It's just that 1st one is a CallExpression
that consists of FunctionExpression
followed by Arguments
, whereas 2nd one is a CallExpression
that consists of Identifier
followed by Arguments
.
Both still resolve to a function object, which has internal [[Call]] method, which is what gets executed.