I'm looking at section 13 or the ECMAScript specification (v. 5). An anonymous function expression is initialized as follows:
Return the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.
this logic is very similar to how a function declaration is initialized. However, notice how different initialization of a named funciton expression is.
- Let funcEnv be the result of calling NewDeclarativeEnvironment passing the running execution context’s Lexical Environment as the argument
- Let envRec be funcEnv’s environment record.
- Call the CreateImmutableBinding concrete method of envRec passing the String value of Identifier as the argument.
- Let closure be the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in funcEnv as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.
- Call the InitializeImmutableBinding concrete method of envRec passing the String value of Identifier and closure as the arguments.
- Return closure.
I know one of the big differences between named/anonymous function expressions is that named function expressions can be called recursively from within the function, but that's all I can think of. Why is the setup so different and why does it need to do those extra steps?
Anonymous functions are never hoisted (loaded into memory at compilation). Named functions are hoisted (loaded into memory at compilation). When invoking an anonymous function, you can only call it after the declaration line. A name function can be invoked before declaration.
As you've seen, the two syntaxes are similar. The most obvious difference is that function expressions are anonymous, while function declarations have a name. Today, you would typically use a function declaration when you need to do something that function expressions cannot do.
In short, use function declarations when you want to create a function on the global scope and make it available throughout your code. Use function expressions to limit where the function is available, keep your global scope light, and maintain clean syntax.
The main difference between a function expression and a function declaration is the function name, which can be omitted in function expressions to create anonymous functions. A function expression can be used as an IIFE (Immediately Invoked Function Expression) which runs as soon as it is defined.
The reason for all that "dancing" is simple.
The identifier of named function expression needs to be made available within function scope but not outside.
typeof f; // undefined
(function f() {
typeof f; // function
})();
How do you make f
available within function?
You can't create binding in the outer Lexical Environment since f
shouldn't be available outside. And you can't create binding in the inner Variable Environment since... it's not yet created; the function is not yet executed at the moment of instantiation, and so 10.4.3 (Entering Function Code) step with its NewDeclarativeEnvironment has never happened.
So the way this is done is by creating an intermediate lexical environment that "inherits" directly from current one, and which is then passed as [[Scope]] into the newly created function.
You can see this clearly if we break steps in 13 into pseudo code:
// create new binding layer
funcEnv = NewDeclarativeEnvironment(current Lexical Environment)
envRec = funcEnv
// give it function's identifier
envRec.CreateImmutableBinding(Identifier)
// create function with this intermediate binding layer
closure = CreateNewFunction(funcEnv)
// assign newly created function to an identifier within this intermediate binding layer
envRec.InitializeImmutableBinding(Identifier, closure)
So the lexical environment within f
(when resolving identifier, for example) now looks like this:
(function f(){
[global environment] <- [f: function(){}] <- [Current Variable Environment]
})();
With anonymous function it would look like this:
(function() {
[global environment] <- [Current Variable Environment]
})();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With