1. 程式人生 > >關於javascript閉包(Closure)和return之間的曖昧關係

關於javascript閉包(Closure)和return之間的曖昧關係

  什麼是閉包阮一峰老師說的很清楚了,定義在一個函式內部的函式,在本質上,閉包就是將函式內部和函式外部連線起來的一座橋樑

  首先要了解Javascript的變數作用域:全域性變數區域性變數。全域性嘛,就是共享,任何一個函式內部可以直接讀取全域性變數;區域性嘛,就是私有,不暴露在外的。如何判斷該變數是全域性還是區域性,函式內部看它有沒有var進行宣告。沒有var宣告的變數,實際是個全域性變數,別被騙咯!

傲嬌的小眼神(別被騙咯)

  Javascript語言特有的"鏈式作用域"結構(chain scope),子物件會一級一級地向上尋找所有父物件的變數。所以,父物件的所有變數,對子物件都是可見的,反之則不成立。既然子物件可以讀取父物件的變數,那我們想獲取一個物件(假設為f1)裡面的變數,給f1建立一個子物件(假設為f2),並將子物件return出去,不就可以在外部訪問到這個物件(f1)的私有變數。f2就是閉包,沒錯,它就是閉包。不多說,程式碼如圖:

f2即為閉包

  那麼問題來了,你說閉包是為了獲取一個函式內部的私有資料而建立的,那我直接將一個想要獲取的資料return出去,外部不一樣可以獲取嘛,不多說,看權威的jquery原始碼:

我非要return

外部訪問資料

  也有人說閉包可以防止全域性變數汙染,什麼是全域性變數汙染?當多人一起開發一個大型專案的時候,每個人負責一塊,其中定義的全域性變數可能會存在命名衝突,當專案進行整合的時候起衝突的全域性變數會被覆蓋,這應該很好理解。閉包的應用將變數私有化,可以起到防止變數全域性汙染的作用,外部同時也可以訪問到私有化的變數。解決全域性變數汙染的問題,可以結合js模組化開發思維,如下圖:

js模組化一

js模組化二(閉包)

  兩者的區別在圖片中已經闡明瞭,可以自行試一試。閉包還有一個比較大的用處,相信你們都知道,讓這些變數的值始終保持在記憶體中。所以注意的一點就是:由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。(阮一峰老師原話,偷點懶0.0)。

  這句話不知道你們能否瞭解,我簡單闡述下我的想法,一定要認真看完哈!首先全域性變數和區域性變數生命週期是不同的,全域性變數存放在一個區域內,具有全域性作用域;區域性變數放在堆疊中,由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,只有區域性作用域,在程式執行期間不是一直存在,而是隻在函式執行期間存在,函式的一次呼叫執行結束後,變數被撤銷,其所佔用的記憶體也被收回(GC)

垃圾回收機制(GC)原理:垃圾收集器會按照固定的時間間隔,週期性找出不再使用的變數,然後釋放其佔用的記憶體。不再使用的變數也就是生命週期結束的變數,是區域性變數,區域性變數只在函式的執行過程中存在,當函式執行結束,沒有其他引用(閉包),那麼該變數會被標記回收。全域性變數的生命週期直至瀏覽器解除安裝頁面才會結束,也就是說全域性變數不會被當成垃圾回收。當一個區域性變數存在引用(閉包),該變數也不會被當成垃圾回收,始終存在於記憶體中。

  閉包這種將變數始終儲存,大家知道有什麼好處麼?可以仔細研究想想,再深剖會發現,閉包在效能優化方面優勢很明顯,對比下return,如圖所示:

閉包與return對比

  如上程式碼,通過閉包,在外部對資料進行操作時候,紅框內程式碼不會再一次執行,也就是f1裡面劈里啪啦一頓猛如虎的操作之後獲得的n,儲存到記憶體中後,外部操作實際上是對儲存在記憶體上的資料進行了操作。相比return,如果外部想獲得內部的私有資料再操作,那內部的程式在外部每獲取一次就需要跑一次,這無形中消耗著電腦的效能,所以我覺得,閉包的合理使用,是可以降低電腦效能的消耗起到一定的優化效能的作用。不合理的使用閉包會導致記憶體洩漏。

  好了,謝謝你這麼帥,還能看完我的分享,希望對你有所幫助(辛辛苦苦寫了那麼多,兄dei,點個贊再走吧),送你一朵❀。