函數申明與函數表達式【翻譯】

函數聲明與表達式

函數和變量同樣,能夠在代碼的任何地方定義。
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。

  • 使用動詞命名函數。短命名容許被用在兩種狀況:被用在附近代碼塊,或被很是普遍使用。
    圖片描述

整體來講,推薦使用函數聲明,除非有緣由須要使用函數表達式。

相關文章
相關標籤/搜索