1. 程式人生 > >深入理解JavaScript系列(2):揭祕命名函式表示式

深入理解JavaScript系列(2):揭祕命名函式表示式

這裡寫圖片描述 這裡寫圖片描述 還有一種函式表示式不太常見,就是被括號括住的(function foo(){}),他是表示式的原因是因為括號 ()是一個分組操作符,它的內部只能包含表示式,我們來看幾個例子:

這裡寫圖片描述 函式宣告只能出現在程式或函式體內。 如果function foo(){}是作為賦值表示式的一部分的話,那它就是一個函式表示式,如果function foo(){}被包含在一個函式體內,或者位於程式的最頂部的話,那它就是一個函式宣告。

2、命名函式表示式

正如我們開頭所說:給它一個名字就是可以讓除錯過程更方便,因為在除錯的時候,如果在呼叫棧中的每個項都有自己的名字來描述,那麼除錯過程就太爽了,感受不一樣嘛。

var bar = function foo(){};就是一個有效的命名函式表示式,但有一點需要記住:這個名字只在新定義的函式作用域內有效,因為規範規定了標示符不能在外圍的作用域內有效: 這裡寫圖片描述

這裡寫圖片描述 按照程式碼的分析,我們原本是想建立一個全域性屬性f(注意不要和一般的匿名函式混淆了,裡面用的是帶名字的生命),JScript在這裡搗亂了一把,首先他把表示式當成函式宣告解析了,所以左邊的f被宣告為區域性變量了(和一般的匿名函式裡的宣告一樣),然後在函式執行的時候,f已經是定義過的了,右邊的function f(){}則直接就賦值給區域性變數f了,所以f根本就不是全域性屬性。

JScript的記憶體管理

這裡寫圖片描述 我們知道,這個匿名函式呼叫返回的函式(帶有識別符號g的函式),然後賦值給了外部的f。我們也知道,命名函式表示式會導致產生多餘的函式物件,而該物件與返回的函式物件不是一回事。所以這個多餘的g函式就死在了返回函式的閉包中了,因此記憶體問題就出現了。這是因為if語句內部的函式與g是在同一個作用域中被宣告的。這種情況下 ,除非我們顯式斷開對g函式的引用,否則它一直佔著記憶體不放。

這裡寫圖片描述

通過設定g為null,垃圾回收器就把g引用的那個隱式函式給回收掉了,為了驗證我們的程式碼,我們來做一些測試,以確保我們的記憶體被回收了。

在命名函式表示式被求值時,會建立一個特殊的物件,該物件的唯一目的就是儲存一個屬性,而這個屬性的名字對應著函式識別符號,屬性的值對應著那個函式。 這個物件會被注入到當前作用域鏈的前端。

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述 這裡寫圖片描述