通常定義函數有兩種方式:javascript
以下方法
add
就是函數聲明的代碼結構:html
function add(x,y){
alert(x+y)
}
add(1,2) //彈窗顯示:3
複製代碼
關於函數聲明,它最重要的一個特徵就是函數聲明提高,意思是執行代碼以前先讀取函數聲明。這意味着能夠把函數聲明放在調用它的語句以後。以下代碼能夠正確執行:java
add(1,2); //彈窗顯示:3
function add(x,y){
alert(x+y)
}
複製代碼
函數表達式中有幾種不一樣的語法。最多見和最具表明性的一種以下所示:bash
var add = function(x,y){
alert(x+y)
}
add(1,2) //彈窗顯示:3
複製代碼
這種形式看起來好像是常規的變量賦值語句。可是函數表達式和函數聲明的區別在於,函數表達式在使用前必須先賦值。因此這段代碼執行的時候就會出錯:函數
add(1,2) //無彈窗,報錯: add is not a function
var add = function(x,y){
alert(x+y)
}
複製代碼
形成這種現象是由於解析器在向執行環境中加載數據時,解析器會率先讀取函數聲明,並使其在執行任何代碼前可用;至於函數表達式,則必須等到解析器執行到它的所在的的代碼行,纔會真正的被解析。函數表達式中,建立的函數叫作匿名函數,由於function關鍵字後面沒有標識符。測試
匿名函數,顧名思義就是沒有名字的函數。上面的函數表達式中的建立,其實是建立一個匿名函數,並將匿名函數賦值給變量 add
,用 add
來進行函數的調用,調用的方式就是在變量 add
後面加上一對括號(),若是有參數傳入的話就是 add(1,2)
,這就是匿名函數的一種調用方式。ui
還有一種匿名函數的調用方式是:使用()將匿名函數括起來,而後後面再加一對小括號(包含參數列表)。咱們再看一下如下一個例子:spa
alert((function(x,y){return x+y;})(2,3)) //彈窗提示5
alert((new Function("x","y","return x+y"))(2,3)) //彈窗顯示5
複製代碼
在javascript中,是沒有塊級做用域這種說法的,以上代碼的這種方式就是模仿了塊級做用域(一般成爲私有做用域),語法以下所示:.net
(function(){
//這裏是塊級做用域
})();
複製代碼
以上代碼定義並當即調用了一個匿名函數。經函數聲明包含在一對圓括號中,表示它其實是一個函數表達式。而緊隨其後的另外一對圓括號會當即調用這個函數。然而要注意一點:code
function(){
}();
複製代碼
上面的代碼是錯誤的,由於Javascript將function關鍵字看成一個函數聲明的開始,而函數聲明後面不能加圓括號,若是你不顯示告訴編譯器,它會默認生成一個缺乏名字的function,而且拋出一個語法錯誤,由於function聲明須要一個名字。有趣的是,即使你爲上面那個錯誤的代碼加上一個名字,他也會提示語法錯誤,只不過和上面的緣由不同。提示爲:Uncaught SyntaxError: Unexpected token (
。
在一個表達式後面加上括號(),該表達式會當即執行,可是在一個語句後面加上括號(),是徹底不同的意思,只是分組操做符。
function foo(){
alert('測試是否彈窗')
}()
// SyntaxError: Unexpected token )
// 報錯由於分組操做符須要包含表達式
function foo(){
alert('測試是否彈窗')
}(1)
// (1) => 等價於 1
// 至關於foo方法後面個跟了一個無關係的表達式子:(1)
複製代碼
因此上面代碼要是想要獲得想要的彈窗提示,就必需要實現賦值,如
a = function(){
alert('測試是否彈窗')
}()
// 彈窗提示成功
複製代碼
"a="
這個片斷告訴了編譯器這個是一個函數表達式,而不是函數的聲明。由於函數表達式後面能夠跟圓括號。
所以下面兩段代碼是等價的
var aa = function(x){
alert(x)
}(5) //彈窗顯示:5
複製代碼
(function(x){
alert(x)
})(5) //彈窗顯示:5
複製代碼
從上面對於函數和匿名函數的瞭解,咱們引伸出來了一個概念,即自執行函數。那爲何 a =function(){}()
這種表示方法可讓編譯器認爲這個是一個函數表達式而不是一個函數的聲明?
自執行函數,即定義和調用合爲一體。咱們建立了一個匿名的函數,並當即執行它,因爲外部沒法引用它內部的變量,所以在執行完後很快就會被釋放,關鍵是這種機制不會污染全局對象。
下面咱們來看下一些比較有趣的自執行函數表達方式:
// 下面2個括弧()都會當即執行
(function () { /* code */ } ()) // 推薦使用這個
(function () { /* code */ })() // 可是這個也是能夠用的
// 因爲括弧()和JS的&&,異或,逗號等操做符是在函數表達式和函數聲明上消除歧義的
// 因此一旦解析器知道其中一個已是表達式了,其它的也都默認爲表達式了
var i = function () { return 10; } ();
true && function () { /* code */ } ();
0, function () { /* code */ } ();
// 若是你不在乎返回值,或者不怕難以閱讀
// 你甚至能夠在function前面加一元操做符號
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
// 還有一個狀況,使用new關鍵字,也能夠用,但我不肯定它的效率
// http://twitter.com/kuvos/status/18209252090847232
new function () { /* code */ }
new function () { /* code */ } () // 若是須要傳遞參數,只須要加上括弧()
複製代碼
看到這裏相信你們對函數有了全新的認識,但願可以幫助到你們。
文中如有寫的不對或須要改進的或者有不一樣的簡介歡迎回復一塊兒探討。😛
📖 參考連接