1. 程式人生 > >什麼是閉包及閉包的優缺點

什麼是閉包及閉包的優缺點

1、什麼是作用域鏈?

在理解閉包以前.最好能先理解一下作用域鏈的含義,簡單來說,作用域鏈就是函式在定義的時候建立的,用於尋找使用到的變數的值的一個索引,而他內部的規則是,把函式自身的本地變數放在最前面,把自身的父級函式中的變數放在其次,把再高一級函式中的變數放在更後面,以此類推直至全域性物件為止.當函式中需要查詢一個變數的值的時候,js直譯器會去作用域鏈去查詢,從最前面的本地變數中先找,如果沒有找到對應的變數,則到下一級的鏈上找,一旦找到了變數,則不再繼續.如果找到最後也沒找到需要的變數,則直譯器返回undefined.

2、Js的記憶體回收機制

瞭解了作用域鏈,我們再來看看js的記憶體回收機制

,一般來說,一個函式在執行開始的時候,會給其中定義的變數劃分記憶體空間儲存,以備後面的語句所用,等到函式執行完畢返回了,這些變數就被認為是無用的了.對應的記憶體空間也就被回收了.下次再執行此函式的時候,所有的變數又回到最初的狀態,重新賦值使用.但是如果這個函式內部又嵌套了另一個函式,而這個函式是有可能在外部被呼叫到的.並且這個內部函式又使用了外部函式的某些變數的話.這種記憶體回收機制就會出現問題.如果在外部函式返回後,又直接呼叫了內部函式,那麼內部函式就無法讀取到他所需要的外部函式中變數的值了.所以js直譯器在遇到函式定義的時候,會自動把函式和他可能使用的變數(包括本地變數和父級和祖先級函式的變數(自由變數))一起儲存起來.也就是構建一個閉包,這些變數將不會被記憶體回收器所回收,只有當內部的函式不可能被呼叫以後(例如被刪除了,或者沒有了指標),才會銷燬這個閉包,而沒有任何一個閉包引用的變數才會被下一次記憶體回收啟動時所回收.

3、什麼是閉包

閉包是有權訪問另一個函式作用域的變數的函式。 
簡單的說,Javascript允許使用內部函式---即函式定義和函式表示式位於另一個函式的函式體內。而且,這些內部函式可以訪問它們所在的外部函式中宣告的所有區域性變數、引數和宣告的其他內部函式。當其中一個這樣的內部函式在包含它們的外部函式之外被呼叫時,就會形成閉包。

4、閉包的主要作用

閉包可以用在許多地方。它的最大用處有兩個:一個是前面提到的可以讀取函式內部的變數,另一個就是讓這些變數的值始終保持在記憶體中。

5、閉包與this物件

在閉包中使用this物件可能會導致一些問題,因為匿名函式的執行具有全域性性,因此其this物件通常指window

把外部作用域的this物件儲存在一個閉包能夠訪問的變數裡面,就可以讓閉包訪問物件了,

6、閉包與記憶體洩漏

具體來說,如果閉包的作用域中儲存著一個html元素,那麼就意味著元素無法被銷燬。

以上程式碼建立了一個作為element元素事件處理程式的閉包,而這個閉包則又建立了一個迴圈引用。由於匿名函式儲存了一個對assignHandler()的活動物件的引用,因此會導致無法減少element的引用數。只有匿名函式存在,element的引用數至少也是1,因此他所佔用的記憶體就不會被回收。

通過寫程式碼來解決內部不能回收問題:

以上程式碼,實現閉包不直接引用element,包含函式的活動物件中也仍然會儲存一個引用。因此,有必要把element的變數設定為null,這樣就可以回收其佔用的記憶體。

7、使用閉包的注意點

1)由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。

2)閉包會在父函式外部,改變父函式內部變數的值。所以,如果你把父函式當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函式內部變數的值。