什么是閉包?阮一峰老師說的很清楚了,定義在一個函數內部的函數,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。
首先要了解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,點個贊再走吧),送你一朵❀。