Preface
In ECMAScript, there are two most commonly used methods to create function objects, namely using function expressions or using function declarations. In this regard, the ECMAScript specification makes it clear that function declarations must always carry an identifier, which is what we call the function name, and function expressions can be omitted. Let’s take a look at the detailed introduction to the differences between the two.
What is Function Declaration?
Function Declaration can define named function variables without assigning values to the variables. Function Declaration is an independent structure that cannot be nested in non-functional modules. It can be compared to Variable Declaration. Just as Variable Declaration must start with "var", Function Declaration must start with "function".
For example
function bar() { return 3;}ECMA 5 (13.0) definition syntax:
function Identifier ( FormalParameterList[opt] ) { FunctionBody }
Function names are available within their own scope and parent scope (otherwise the function will not be available).
function bar() { return 3;} bar() //3bar //functionWhat is Function Expression?
Function Expression Defines a function as part of an expression statement (usually variable assignment). Functions defined by Function Expression can be named or anonymous. Function Expression cannot begin with "function" (the following self-call examples should be enclosed in brackets).
For example
//anonymous function expressionvar a = function() { return 3;} //named function expressionvar a = function bar() { return 3;} //self invoking function expression(function saysHello() { alert("hello!");})();ECMA 5 (13.0) definition syntax:
function Identifieropt ( FormalParameterList[opt] ) { FunctionBody }
(This definition feels incomplete because it ignores a condition: the peripheral statement is an expression and does not start with "function")
Function names (if any) are not available outside scope (compared with Function Declaration).
So what is Function Statement?
Function Statement is sometimes another way of Function Declaration. But kangax points out that in mozilla, Function Statement is an extension of Function Declaration, allowing the Function Declaration statement to be used anywhere that allows the use of statements. However, Function Statement is not the standard now, so it is not recommended to be used in product development.
Let's start with some small tests. Guess what will pop up in the following situations?
Question 1:
function foo(){ function bar() { return 3; } return bar(); function bar() { return 8; }}alert(foo());Question 2:
function foo(){ var bar = function() { return 3; }; return bar(); var bar = function() { return 8; };}alert(foo());Question 3:
alert(foo());function foo(){ var bar = function() { return 3; }; return bar(); var bar = function() { return 8; };}Question 4:
function foo(){ return bar(); var bar = function() { return 3; }; var bar = function() { return 8; };}alert(foo());If your answer is not 8, 3, 3 and [Type Error: bar is not a function], then continue reading... (Even if you answer correctly, you must continue reading)
Now let’s explain the previous test.
Question 1 uses function declaration, which means they get hoisted...
Wait, what is Hoisting?
Here is a quote from Ben Cherry: "Function declaration and function variable are usually moved ('hoisted') to the top of the current scope by the JavaScript interpreter."
When function declaration is promoted, the entire function body will be promoted accordingly, so the code of Question 1 runs like this after being explained by the interpreter:
//**Simulated processing sequence for Question 1**function foo(){ //define bar once function bar() { return 3; } //redefine it function bar() { return 8; } //return its invocation return bar(); //8}alert(foo());However, we are often told that the code behind the return statement cannot run...
During the execution of JavaScript, there are two concepts: Context (ECMA 5 breaks it down into LexicalEnvironment, VariableEnvironment and ThisBinding) and Process (a series of statements called in sequence). When the program enters the execution domain, Declaration causes VariableEnvironment. They are different from Statement (such as return) and do not follow Statement running rules.
Will Function Expression be promoted?
It depends on the expression. For example, the first expression in Question 2:
var bar = function() { return 3;};The (var bar) on the left of the equal sign is Variable Declaration. Variable Declaration will be promoted, but Assignment Expression will not. So when bar is promoted, the interpreter will be initialized like this: var bar = undefined. The function definition itself will not be promoted.
(ECMA 5 12.2 Variables with initialzier are assigned by AssignmentExpression when VariableStatement is executed, not when the variable is created.)
Therefore, the code of Question 2 will be run in the following order:
//**Simulated processing sequence for Question 2**function foo(){ //a declaration for each function expression var bar = undefined; var bar = undefined; //first Function Expression is executed bar = function() { return 3; }; // Function created by first Function Expression is invoked return bar(); // second Function Expression unreachable}alert(foo()); //3You may say that this can be explained, but the answer to Question 3 is wrong. I will report an error when running Firebug.
Save the code in an HTML file and try running it on Firefox. Or run in IE8, Chrome, or Safari console. Obviously, the Firebug console will not promote the function when running the code in the "global" scope (actually not global, but the unique "Firebug" scope - just try to run "this == window" in the Firebug console).
Question 3 and Question 1 have similar logic. This time the foo function was promoted.
Question 4 is very simple, there is no function improvement at all...
It can be said that, but if there is no improvement at all, the TypeError will be "bar not defined" instead of "bar not a function". There is indeed no function improvement in this example, but there is variable improvement. Therefore, bar is declared at the beginning, but its value is not defined. The other codes are executed in order.
//**Simulated processing sequence for Question 4**function foo(){ //a declaration for each function expression var bar = undefined; var bar = undefined; return bar(); //TypeError: "bar not defined" //neither Function Expression is reached}alert(foo());What else should you pay attention to?
The official prohibits the use of Function Declaration in non-functional modules (such as if). However, all browsers support it, but their explanations are different.
For example, the following code snippet will throw an error in Firefox 3.6 because it interprets Function Declaration as Function Statement (see above), so x is not defined. But in IE8, Chrome 5 and Safari 5, the function x will be returned (same as standard Function Declaration).
function foo() { if(false) { function x() {}; } return x;}alert(foo());It can be seen that using Function Declaration may cause confusion, so do it have any advantages?
You might say that Function Declaration is quite loose - if you try to use a function before declaration, the promotion can indeed correct the order so that the function can be called correctly. But this kind of looseness is not conducive to rigorous coding, and from a long-term perspective, it is likely to promote rather than prevent accidents. After all, there is a reason programmers arrange statements in a specific order.
So are there any other reasons to support Function Expression?
What do you think?
1) Function Declaration feels like it is to imitate Java-style method declarations, but Java methods are not the same as JavaScript. In JavaScript, functions are living objects with values. Java methods are only storage of metadata. The following two pieces of code define the function, but only Function Expression looks like an object is created.
//Function Declarationfunction add(a,b) {return a + b};//Function Expressionvar add = function(a,b) {return a + b};2) Function Expression has more uses. Function Declaration can only exist in orphans as a "statement". All it can do is create an object variable under the current scope. Function Expression, by definition, is part of a large structure. If you want to create anonymous functions, add functions to prototypes, or use functions as property of other objects, you can use Function Expression. Whenever you use advanced applications, such as curry or compose, you use Function Expression when creating new functions. Function Expression and Functional Programming are inseparable.
//Function Expressionvar saysHello = alert.curry("hello!");Are there any drawbacks in Function Expression?
Function Expression creates most functions anonymous. For example, the following function is anonymous, today is just a reference to an anonymous function:
var today = function() {return new Date()}Will this be problematic? Not in most cases, but as Nick Fitzgerald pointed out, debugging anonymous functions can be annoying. He recommends using Named Function Expressions (NFEs) as the workspace:
var today = function today() {return new Date()}However, as Asen Bozhilov said (and Kangax documentation) NFEs cannot be executed correctly below IE9.
in conclusion
A randomly placed Function Declaration is misleading and rarely (if any) situations, and assigning values to variables with Function Expression cannot replace Function Declaration. But if Function Declaration is required, putting it at the top of the scope can reduce confusion. Never put Function Declaration in an if statement.
Having said so much, Function Declaration may be useful in your own situation. It's nothing. Role dogma is dangerous and often causes code to be beat around the bush. More importantly, you understand the concept so that you can decide which method to create the function based on your own situation. The above is the entire content of this article. I hope this article will be helpful to everyone in this regard.