最近在看《Javascript for Web Developers》积暖,雖然在VT項目中的一個小demo中擔(dān)任了前端工程師,開始了javascript之路郑象,但是真正來看javascript高級語法的時候還是懵逼了册烈。
function declaration 和 function expression在講function的時候貌似講到了弥姻,當(dāng)時看的時候也是以為自己記得了强经,再看塊作用域的時候還是不太清楚睡陪。于是在網(wǎng)上找到了一篇文章,看完做個記錄也好匿情。
什么是 javascript declaration
Function declaration定義了一個命名的函數(shù)變量兰迫,但是并沒有變量賦值(without requiring variable assignment.)。 Function declration必須作為一個單獨的構(gòu)造器出現(xiàn)炬称,而不能被放在no-function的塊中汁果。
可以簡單地這么想,function declaration 就想variable declaration的兄弟一樣玲躯,只是變量聲明首先寫的是var, 而函數(shù)聲明必須以function開頭据德。
ECMA5 定義的語法是這樣的: function?Identifier(FormalParameterListopt) {FunctionBody}
function bar() {return 3;}
bar(); //3
bar; // function
什么是function expression?
Function Expression定義了一個函數(shù),使它作為一個更大的expression語法的一部分(一般是變量賦值)跷车。 通過Function Expression定義的函數(shù)可以是匿名的棘利, 不需要以function開頭。
//anonymous function expression
var a =function() {
return 3;
}
//named function expression
var a =function bar() {
return 3;
}
//self invoking function expression
(functionsayHello() {
alert("hello!");
})();
ECMA5定義的語法是:function?Identifieropt(FormalParameterListopt) {FunctionBody}
The function name (if any) is not visible outside of its scope (contrast with Function Declarations).
案例一
function ?foo(){
? ? function ?bar() {
? ? return ?3;
? ? ?}
? ?return ?bar();
? ?function bar() {
? ? ? ? return 8;
? ? }
}
alert(foo()); ?//8
Hoisting??
Function declarations and function variables are always moved (‘hoisted’) to the top of their JavaScript scope by the JavaScript interpreter
因此在案例一中姓赤,第二次聲明的bar()被放到return bar(); 語句之前了仲吏,相當(dāng)于重新定義了bar, 然后在invoke了bar(), 因此返回值為8.
我們按照習(xí)慣不铆,總覺得return之后的代碼是執(zhí)行不到的蝌焚?
在Javascript的執(zhí)行過程中有一個Context和process。 Context被分為lexical environment誓斥, variable environment 和 this binding只洒。 declartions在進(jìn)入執(zhí)行域時是在variable中的,與statement不一樣劳坑,因此和它們的執(zhí)行流程不一樣毕谴。
案例二
但是在function expression中就不一樣了。
functionfoo(){
var bar =function() {
return 3;
};
return bar();
var bar =function() {
return 8;
};
}
alert(foo()); // 3
(ECMA 5 12.2 A variable with an?initializer?is assigned the value of itsAssignmentExpressionwhen theVariableStatementis executed, not when the variable is created.)
因此該案例的實際執(zhí)行順序如下
//**Simulated processing sequence for Question 2**
functionfoo(){
//a declaration for each function expression
varbar = undefined;
varbar = undefined;
//first Function Expression is executed
bar =function() {
return3;
};
// Function created by first Function Expression is invoked
returnbar();
// second Function Expression unreachable
}
alert(foo());//3
I can see how using Function Declarations can cause confusion but are there any benefits?
Well you could argue that Function Declarations are forgiving – if you try to use a function before it is declared, hoisting fixes the order and the function gets called without mishap. But that kind of forgiveness does not encourage tight coding and in the long run is probably more likely to promote surprises than prevent them. After all, programmers arrange their statements in a particular sequence for a reason.
And there are other reasons to favor Function Expressions?
How did you guess?
a) Function Declarations feel like they were intended to mimic Java-style method declarations but Java methods are very different animals. In JavaScript functions are living objects with values. Java methods are just metadata storage. Both the following snippets define functions but only the Function Expression suggests that we are creating an object.
//Function Declaration
function add(a,b) {returna + b};
//Function Expression
var add =function(a,b) {returna + b};
b) Function Expressions are more versatile. A Function Declaration can only exist as a “statement” in isolation. All it can do is create an object variable parented by its current scope. In contrast, a Function Expression (by definition) is part of a larger construct. If you want to create an anonymous function or assign a function to a prototype or as a property of some other object you need a Function Expression. Whenever you create a new function using a high order application such as?curry?or?compose?you are using a Function Expression. Function Expressions and Functional Programming are inseparable.
//Function Expression
var sayHello = alert.curry("hello!");
Do Function Expressions have any drawbacks?
Typically functions created by Function Expressions are unnamed. For instance, the following function is anonymous,today is just a reference to an unnamed function:
1
var today = function() {return newDate()}
Does this really matter? Mostly it doesn’t, but as?Nick Fitzgerald?has pointed out debugging with anonymous functions can be frustrating. He suggests using Named Function Expressions (NFEs) as a workaround:
1
var today =function today() {returnnewDate()}
However as Asen Bozhilov points out (and Kangax?documents) NFEs do not work correctly in IE < 9
Conclusions?
Badly placed Function Declarations are misleading and there are few (if any) situations where you can’t use a Function Expression assigned to a variable instead. However if you must use Function Declarations, it will minimize confusion if you place them at the top of the scope to which they belong. I would never place a Function Declarations in an?if?statement.
Having said all this you may well find yourself in situations where it makes sense to use a Function Declaration. That’s fine. Slavish adherence to rules is dangerous and often results in tortuous code. Much more important is that you understand the concepts so that you can make your own informed decisions. I hope this article helps in that regard.