函數和變量同樣,能夠在代碼的任何地方定義。
JavaScript提供一些方式去定義方法:javascript
函數聲明java
函數表達式express
函數做爲另外一個函數結果被調用瀏覽器
基本建立函數的語法是函數聲明。語法以下:函數
function f(arg1, arg2, ...) { ... code ... }
好比:spa
function sayHi(name) { alert("Hi, "+name) } sayHi('John')
這個例子聲明一個只有一個參數的函數sayHi,運行sayHi。code
用return聲明來返回值對象
function sum(a, b) { return a+b } var result = sum(2,5) alert(result)
若是函數沒有返回值,結果被認爲是一個特殊值「undefined」。以下例:遞歸
function getNothing() { // no return } var result = getNothing() alert(result)
返回空值也是同樣結果:圖片
function getNothing() { return } alert( getNothing() === undefined ) // true
函數內能夠包含變量,用var來定義。這種變量叫作局部變量,只能被內部函數訪問。
function sum(a, b) { var sum = a + b return sum }
建立一個函數min(a,b),接收兩個數字,返回一個較小的值。
min(2, 5) == 2
min(3, -1) == -1
答案
方案一 用if判斷:
function min(a, b) { if (a < b) { return a } else { return b } }
方案二 用三目運算符:
function min(a, b) { return a < b ? a : b // 若是是true運行a,不然運行b }
寫一個函數pow(x,n)返回x的n次方,或者說,x被本身乘了n次。
pow(3, 2) = 3*3 = 9
pow(3, 3) = 333 = 27
pow(1, 100) = 11...*1 = 1
function(x,n){ var result for(var i = 0;i<n;i++){ result*=x; } return result; }
函數聲明在預執行階段(當瀏覽器準備執行代碼)解析。因此函數聲明在先後都能被調用到。
function sayHi(name) { alert("Hi, "+name) } sayHi("John")
sayHi("John") function sayHi(name) { alert("Hi, "+name) }
因此函數在任何位置均可以聲明
好比,咱們可能但願根據條件聲明不一樣的函數
sayHi() if (1) { function sayHi() { alert(1) } } else { function sayHi() { alert(2) } // <-- }
嘗試在不一樣瀏覽器中運行這個例子。火狐會報錯,其餘瀏覽器輸出2。
那是由於聲明在執行前被傳遞了。根據文檔(p.10.5),後同名的函數,後
聲明的會覆蓋存在的函數。
當執行時,其餘聲明會被忽略,因此if語句沒有任何效果。
函數表達式
JavaScript中函數是一等公民,和數字字符同樣。
在任何你能夠寫值的地方,你均可以寫函數。函數表達式的語法
function(arguments) { ... }
舉例,你能夠寫
var f = 5
但你也能夠賦函數表達式
var f = function(name) { alert("Hi, " + name + "!"); }
何時函數是表達式,何時是聲明呢?
規則很簡單。
但javascript解析器在主代碼流中,他會認爲這是函數聲明。
當函數是聲明語句的一部分是,他就是函數表達式。
當執行流到達函數表達式被建立,結果是,函數表達式只有他們被執行後才能使用。
var sayHi // sayHi() <-- 這裏不能執行,尚未sayHi函數 if (1) { sayHi = function() { alert(1) } } else { sayHi = function() { alert(2) } } sayHi()
上述代碼全部瀏覽器執行結果相同。
請用聲明
經驗不足的開發人員寫的代碼中,方法常常用表達式來聲明:
var f = function() { ... }
函數聲明更加可讀簡潔,仍是用函數聲明吧。
function f() { ... }
除此之外,函數聲明可在定義前調用。
只有你在執意要用函數表達式時採用。如例子中,條件性的函數定義。
函數是值
javascript中的函數是通常值,咱們能夠輸出他。
function f() { alert(1) } alert(f)
上面這個輸出函數的例子。一般用做源代碼。( Usually as the source code.)
Both declarations and expression declare a variable and put the function into it. Only the creation time is different.
聲明和表達式均可以做爲變量的值。只是建立的時間不一樣。
傳遞函數
函數和任何值同樣能夠被賦值,作爲其餘函數的參數傳遞等。
以下例,怎麼定義函數沒有關係。
function sayHi(name) { alert("Hi, "+name) } var hi = sayHi // 把函數賦值給變量 hi("dude") // 執行函數
函數經過引用被賦值。函數保存在內存的某處,sayHi是它的引用(指向)。當我把函數賦值給hi,變量開始引用同一個函數。
一個函數能夠接受另外一個函數作爲參數
function runWithOne(f) { // 運行作爲參數1的函數 f(1) } runWithOne( function(a){ alert(a) } )
邏輯上說,函數是一個動做.那麼,傳遞函數是傳遞一個動做,可以在程序另外一部分來初始化。這種特性在javascript中被普遍使用。
在上面的例子中,咱們建立一個沒有名字的函數,沒有賦值給任何變量。這樣的函數叫匿名函數。
就地執行
能夠用函數表達式建立並當即運行函數,像這樣:
(function() { var a, b // 局部變量 // ... // 其餘代碼 })()
當即執行函數大多被用在咱們想作一些圍繞局部變量的事情。咱們不想咱們的局部變量變成全局,因此包含在函數裏面。
在執行後,全局命名空間仍是很乾淨,很好的實踐。
那爲何函數在括號中?是由於javascript只容許函數表達式當即執行。
函數聲明不能被這樣用:
function work() { // ... }() // 語法錯誤
即便咱們去掉名稱,javaScript會看到關鍵詞函數,嘗試轉換成函數聲明。
function() { // 錯誤,沒有名稱的函數聲明。 // ... }()
那麼。惟一的方式是把函數用括號包起來。就會打斷他被認爲是聲明的一部分,因此是函數表達式。
若是函數是一個明顯的表達式,那就不必包起來,以下:
var result = function(a,b) { return a+b }(2,2) alert(result) // 4
在上面的代碼中,函數被建立且當即調用。
就像var result = sum(2,2),用sum函數替換函數表達式。
下面的代碼執行結果是什麼?爲何?
var a = 5 (function() { alert(a) })()
答案:
答案是error,嘗試下面代碼:
var a = 5 (function() { alert(a) })()
在var a = 5後面沒有分號。JavaScript把代碼認爲是:
var a = 5(function() { alert(a) })()
那麼,他會嘗試運行5作爲一個函數,這就會形成錯誤。能運行的代碼以下:
var a = 5; (function() { alert(a) })()
這可能JavaScript中是最危險隱蔽的不寫分號。
還有一種方式直接調用函數構造器。把參數列表和函數做爲字符串,用他們建立函數。
var sayHi = new Function('name', ' alert("Hi, "+name) '); sayHi("Benedict");
這種方式用的不多不多,幾乎不用。
命名函數表達式
一個函數表達式可有名字:
var f = function sayHi(name) { alert("Hi, "+name) }
語法叫命名函數表達式(NFE)在任何瀏覽器均可用除了IE9如下。
在那些支持的瀏覽器中,名字只在函數內可見
var f = function sayHi(name) { alert(sayHi) // 輸出函數 } alert(sayHi) // 錯誤:爲定義的變量'sayHi'
在這種狀況IE會建立兩個函數對象:sayHi和f:
var f = function g() { } // IE中是false,其餘瀏覽器報錯(g爲定義) alert(f=== g)
NEFS存在是爲了遞歸匿名函數。
觀察下面代碼片斷被包在serTimeout中調用:
setTimeout(function factorial(n) { return n == 1 ? n : n*factorial(n-1) }, 100)
代碼的結果是什麼?爲何?
( function g() { return 1 } ) alert(g)
答案:
結果是error:
( function g() { return 1 } ) alert(g)
解決方案的關鍵是理解(function ... )是一個函數表達式(參考本章),不是函數聲明。
那麼,咱們有一個有名函數表達式。
有名函數表達式的名字只在內部可見。
除了IE9.0如下,全部瀏覽器都支持NFEs,那麼他們會給出錯誤「undefined variable」,由於g只有在函數內部可見。
ie9.0如下不支持NFE,就會輸出函數
函數命名
函數是一個動做。因此命名應該是動詞,像get,read,caculateSum,等等。
短函數名稱的規則:
一個函數是臨時的且只使用在附近的代碼。變量的短命名可用這個邏輯。
一個函數用在代碼任何地方。一方米昂,沒有忘記他的危險,另外一方面,你能夠寫的更少。
真實的例子‘$’, ‘$$’, ‘$A’, ‘$F’ 等。
JavaScript庫中頻繁調用的函數用這些短名稱。
其餘狀況,函數的名字應該是一個動詞,或者一個動詞開頭的多個詞疊加。
總結
JavaScript中函數是普通值。他們能夠按需求被賦值,傳遞,調用。
一個不返回值的函數事實上會返回一個特殊值:undefined。
使用動詞命名函數。短命名容許被用在兩種狀況:被用在附近代碼塊,或被很是普遍使用。
整體來講,推薦使用函數聲明,除非有緣由須要使用函數表達式。