My question is based on the example from a book "Object Oriented JavaScript" (page 81 - Lexical Scope)
So, i understand from this example ...
function f1(){var a = 1; f2();}
function f2(){return a;}
f1();
... that:
a is not defined
But, how f1 get's to know about f2, which is defined after f1 ?
This behavior raises a question:
How JavaScript interpreter works ?
I assume, that it:
- scans the code and simply stores the functions, not assigned to any var, in a global environment
- Invokes a function in ad-hoc way: when there is no such a function in a global environment, then plain.
My question is based on the example from a book "Object Oriented JavaScript" (page 81 - Lexical Scope)
So, i understand from this example ...
function f1(){var a = 1; f2();}
function f2(){return a;}
f1();
... that:
a is not defined
But, how f1 get's to know about f2, which is defined after f1 ?
This behavior raises a question:
How JavaScript interpreter works ?
I assume, that it:
- scans the code and simply stores the functions, not assigned to any var, in a global environment
- Invokes a function in ad-hoc way: when there is no such a function in a global environment, then plain.
2 Answers
Reset to default 16Function declarations are processed upon entry into an executable context (e.g., the global context, or a function call), prior to any of the step-by-step code in the context being processed.
So in your code, these things happen (in this order):
- A "variable object" is created for the execution context.
- Entries (actually, literally, properties) on the "variable object" are created for every
var
and function declaration in the context (plus a few other things). In your case, that'sf1
andf2
. Initially the properties have the valueundefined
. - All function declarations are processed, and so:
- The
f1
function is defined and assigned to its property on the variable object. - The
f2
function is defined and assigned to its property on the variable object.
- The
- The
f1();
line is executed, calling thef1
function. - The
f1
code refers tof2
, which it gets from the variable object, and so it's what we expect it to be (a reference to thef2
function).
The more interesting version is this:
f1();
function f1(){var a = 1; f2();}
function f2(){return a;}
...which happens in exactly the same order listed above, because both of the declarations are handled before the first line of step-by-step code.
Function declarations are different from function expressions, which just like any other expression are evaluated when they're reached in the step-by-step execution of the code. A function expression is any time you create a function and use it as a right-hand value, e.g., assign the result to a variable or pass it into another function. Like this:
var f2 = function() {
};
or this
setTimeout(function() {
alert("Hi there");
}, 1000);
Note that we're using the result of the function
statement as the right-hand value (in an assignment, or by passing it into a function). Those are not pre-processed upon entry into an execution context (e.g., not at Step 3 above), they're handled when the flow of code reaches them. Which leads to:
f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};
...which fails, because f2
is undefined as of when it's called.
You can use a declared function's value as a right-hand value without turning it into a function expression (we do that all the time), so long as you do it in two separate statements. So:
alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);
That happens in this order:
foo
is created (since it's defined by a declaration).- The
alert
runs. - The
setTimeout
runs. - (Later)
foo
is called.
One last point: Although they should work, a function expression that includes a function name does not work reliably on all implementations and must, for now, be avoided:
var f = function foo() { ... }; // <== DON'T DO THIS
Or
setTimeout(function foo() { // <== DON'T DO THIS
}, 1000);
Internet Explorer, in particular, has issues with those, and other implementations have at various times as well.
More to explore:
- Poor misunderstood
var
- Closures are not plicated (because it talks about variable objects and how symbols are resolved)
- Anonymouses anonymous (talks more about named function expressions)
you don't have access to variable 'a' inside function f1, because function f2 is not defined inside f1 scope
if you define f2 inside f1:
function f1(){function f2(){return a;} var a = 1; f2();}
f1();
you don't have any problems