天天看點

《JavaScript應用程式設計》一一2.2 函數聲明

本節書摘來華章計算機出版社《javascript應用程式設計》一書中的第2章,第2.2節,作者:eric elliott 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

在javascript中有多種定義函數的方法,不同方法各有優缺點。

在這段代碼中,foo()是一個函數聲明。正如在“變量提升”一節中所提到的,你不能在條件語句中進行函數聲明,這點一定要注意,下面的代碼中,函數聲明将無效:

更為糟糕的是,不同浏覽器對這段代碼的解讀會有差異,是以,盡量避免在條件語句下進行函數聲明,詳情請參見“變量提升”一節。

過度使用函數聲明會導緻子產品中出現大量無關聯函數,因為函數聲明沒有明确定義函數的作用範圍、功能職責,以及互相間的協作方式。

在上述例子中我們将一個函數體指派給變量bar,這種聲明方式我們稱之為函數表達式。

函數表達式的優勢在于,你可以像變量指派操作那樣将函數體指派給變量,它遵循應用正常的流程控制邏輯,這意味着你可以在條件語句中聲明函數表達式。

函數表達式的不足之處在于,你始終需要為函數體指派一個名稱,否則所聲明的函數将變為匿名函數。匿名函數在javascript中很容易被濫用,假設子產品中所有的函數都是匿名函數,而且彼此間互有嵌套(這在事件驅動的應用中非常常見),當嵌套層級達到12層時,恰巧某個環節出了問題,經調試發現調用棧的輸出呈現:

很顯然,調用棧沒有提供給我們任何線索:

這是函數表達式的另外一種聲明方式,将匿名函數作為屬性指派給對象字面量,此時匿名函數被稱為“方法字面量”,方法是指與對象綁定的函數。

方法的優勢在于,可以使用對象字面量将有關聯的函數歸為一組。舉例來說,假設你有一組控制燈泡狀态的函數:

将函數歸類的好處是顯而易見的,代碼變得易讀且富有條理,子產品變得易于了解和維護。

另外,當子產品愈加龐大時,由方法字面量所構成的對象能夠很容易地被拆解并重新排列。舉例來說,假設你負責維護一個控制家中照明、電視、音樂和車庫門api的智能家居子產品,當有新裝置接入進來時,如果家居子產品的api組織采用了方法字面量,那麼将整個子產品拆解為獨立的檔案或子子產品會變得非常簡單。

警告: 盡量不要使用function()構造函數進行函數聲明,這等于做了一次隐式的eval()調用,進而給程式帶來性能損耗與安全隐患等問題,更多内容參見附錄a。

命名函數表達式

如你所見,以上每一種函數聲明方法都有其不足之處。不過有一種函數聲明既可以讓代碼易于組織,又能解決調用棧被匿名函數污染的問題,同時還可以在條件語句中使用。來看看燈泡api的另外一種聲明方式:

命名函數表達式是一種具有名稱的特殊匿名函數,它的名稱不僅可以從函數内部擷取(例如遞歸),還可以在調試時,顯示在調用棧中。

與匿名函數一樣,方法字面量僅僅隻是命名函數表達式存在的一種形式,你可以在程式的任意處通過對變量指派來使用命名函數表達式。命名函數表達式與函數聲明的差別在于,命名函數表達式的函數名稱僅能在函數内部被通路。在函數體之外,你仍然隻能通過被函數指派的變量或形參來獲得函數引用。

警告: ie8會将命名函數表達式解析為函數聲明,是以在同一作用域内,命名函數表達式會與其他變量或者函數存在同名沖突。這個問題已經在ie9中修複,而且沒有在市面上其他浏覽器中出現過。

繼續閱讀