前端亂彈99日之函式是一等公民

weixin_34208283發表於2018-05-20

拖延症晚期癌,每次都是週日最後一個小時才開始動筆,先鄙視下自己

今天要“彈”的是一個有點被說“爛”了的話題,在JavaScript裡,函式是一等公民(哇,聽起來很高大上吧),而同時在這個函數語言程式設計異常火爆的年代,你到底該怎麼理解“函式是一等公民”這句話呢?

其實,我們也可以換個角度來看,在JavaScript裡,任何東西都是物件(嗯,還是要刨掉原始型別),作為一個後端狗,在讀《Java程式設計思想》這部“鉅著”的時候,記得有那麼一句“萬事萬物皆是物件”,那麼在JavaScript裡離這句話就更近了一些,下面就先看一個例子吧

var log = function(a){
  console.log("invoke:"+a);
}
log.name = "日誌";
console.log(log.name);

這裡,我們不僅可以將一個函式賦值給一個變數,甚至還可以給這個變數再增加一個屬性。那麼上面這個log這個到底是個函式呢還是個物件呢?

其實,在JavaScript裡,函式只是一個更特殊的物件,他首先擁有物件的一切能力,接著,他還有額外的一個特殊的部分,可以成為執行部分,或是程式碼部分,那麼接著一個更酷的事情就是,我們可以這樣使用log這個變數。

var log = function(a){
  console.log("invoke:"+a);
}
log.name = "日誌";
log("Just A Test");

這段程式碼,將會輸出

invoke:Just A Test

嗯,如果將一個函式賦值給一個變數之後,我們只需要在這個變數後面增加()即,代表這是一個函式式的物件,可以執行,這裡()更適合一種“運算子”,嗯,就叫執行運算子。

而如果一個變數本身不是指向的了一個函式的話,強行呼叫()會報錯,我們可以試試這樣一段程式碼

var a = {
  "name" : "value"
}
a();

這裡,我們定義了一個變數a,而變數a實際“指向”的是一個物件,並不是函式,這時我們強行呼叫()的話,會報這樣的錯誤:

Uncaught TypeError: a is not a function

報錯資訊很明確,a並不是一個函式。

另外,有關前面曾經聊過的“變數提升”的問題,這裡也是需要再說一說的。

我們之前明確過,一個函式定義是會在執行時環境構建的適合就處理完成,因此一個函式的定義和呼叫的順序是無關的。

比如這段程式碼

log("just a test");
function log(a){
  console.log(a);
}

這裡我們已經很清楚,是可以正確執行的,那麼如果我們換一種方法呢:

log();
var log = function(a){
  console.log(a);
}

這時是會報錯的:

Uncaught TypeError: log is not a function

因為這裡,log只是一個普通的變數,JavaScript的執行時環境並不會把他作為一個函式,對他提前的初始化,這樣的報錯就更好理解了。

那麼對於函數語言程式設計在JavaScript裡的運用,那就更是一個有意思的話題了,今天我們只是框清了一個概念“在JavaScript裡,函式只是一個特殊的物件而已”

相關文章