f1
doesn't have its own x
, so it refers to the global x
, which is 1 and you never change it. f2
does have a local x
in scope which it refers to, which is 100, but there is no code in f2
that ever refers to it! The only console.log
you have is in f1
, referring to the global x
, and you are calling it twice (once from the top-level code and once from inside f2
, but where it's called from doesn't matter)
You are saying the second time f1
is called from f2
's execution context but that doesn't matter, when you call a function a new execution context is created and f2
' s won't have f1
's variables in scope (in its lexical environment to use the correct term here) unless you would nest the whole definition of f1
into f2
. The scopes are fixed* at compile time, they won't change at runtime based on the call stack.
*: In terms of their variables' location in the source code. Since every invocation of a function creates a new scope where those local variables can have new values, technically it is of course set at runtime, but it would still be the same var
/let
/etc in the source code that is referred to every time.
See also: https://javascript.info/closure (this has a great explanation, as already mentioned by Andrejs Kuzmins in the comments)