Javascript閉包詳解

閉包是JavaScript的重要特性,非常強大,可用於執行復雜的計算,可並不容易理解,尤其是對之前從事面向對象編程的人來說,對 JavaScript 認識和編程顯得更難。特別是在看一些開源的JavaScript代碼時感覺尤其如此,跟看天書沒什麼區別。

一般情況下,人們認識一個事物,會根據之前的經驗,進行對比和總結,在腦中建立一個模型,從而理解掌握它,但是JavaScript與面向對象編程實在“沒有可比性”,最明顯的是某過於寫法,總覺得“怪怪的”,更不用說,其一些高級特性。如果說“對象”在面向對象編程時的出現相當有規律,但是在JavaScript中則毫無規律,無處不在,甚至在你意想不到的地方。

首先看兩段代碼。

示例 1:

Javascript閉包詳解

示例 2:

Javascript閉包詳解

示例1 和示例2都是閉包,只是2 比1複雜,甚至還有更復雜的寫法,比如返回多個閉包。

示例 1,腳本被載入內存後,並沒有為函數 sayHelloWorld()計算變量sMessage的值。該函數捕獲 sMessage的值只是為了以後的使用,也就是說,解釋程序知道在調用該函數時要檢查 sMessage 的值。sMessage將在函數調用sayHelloWorld()時(最後一行)被賦值,顯示消息"hello world"。

示例 2,函數addNum()包括函數doAdd() (閉包)。內部函數是一個閉包,因為它將獲取外部函數的參數 iNum1和iNum2以及全局變量 iBaseNum的值。 addNum()的最後一步調用了doAdd(),把兩個參數和全局變量相加,並返回它們的和。

這裡要掌握的重要概念是,doAdd()函數根本不接受參數,它使用的值是從執行環境中獲取的。

閉包,根據 ECMAScript 描述,詞法(lexically)表示包括不被計算的變量的函數,函數可以使用函數之外定義的變量,它意味著當前作用域總能夠訪問外部作用域中的變量。函數是JavaScript中唯一擁有自身作用域的結構,因此閉包的創建依賴於函數。函數內部的函數訪問其所在函數的變量(局部變量、形參),這些變量會受到內部函數的影響,當其外部函數外被調用時,就會形成閉包。內部的函數會在其外部函數返回後,被執行。

示例 3:

Javascript閉包詳解

說明: foo 是bar的外部函數,ba 是foo的內部函數;a是foo的局部變量; bar 訪問foo的局部變量 a; foo 返回bar。 bar在foo的外部被調用。 當執行 baz() 後,閉包使Javascript 垃圾回收機制不會回收foo所佔的資源。因為,baz 實際指向foo的內部函數bar,bar依賴 foo的局部變量a。這樣,在執行var baz=foo()後,baz實際指向了bar,而不是foo。bar訪問了foo的局部變量a,當執行baz()後,a 為20。這就形成了一個閉包。

如果把foo看作是一個包,根據剪頭指示,形成了一個閉包。結果是局部變量a的持久性(如示例 4 所示)。下面代碼就不是閉包。無論執行多少次,都是顯示 20。

Javascript閉包詳解

相關推薦

推薦中...