閉包理解
1.閉包的產生
當一個嵌套的內部函數(子)函數引用了嵌套的外部(父)函數的變量(函數)時,就產生了閉包。
2.閉包到底是什么?
廖雪峰:閉包就是攜帶狀態的函數,並且它的狀態可以完全對外隱藏起來。
理解一(大部分人的理解):閉包是嵌套的內部函數
理解二(少部分人的理解):包含被引用變量(函數)的那個對象(這個對象存在於嵌套的內部函數中)
可以使用開發者工具來調試查看。
3.產生閉包的條件?
(1)存在函數嵌套
(2)嵌套的內部函數必須引用在外部函數中定義的變量(函數)
(3)外部函數被執行(內部的函數不用執行,只需要執行其函數定義就已經產生閉包)
4.產生了幾個閉包
閉包被創建了幾個,就是外部函數被執行了幾次,產生了幾個內部函數對象,因為閉包就是內部函數,只有執行外部函數才會去創建內部函數,和內部函數被執行幾次沒有關系。
常見的閉包
1.將函數作為另一個函數的返回值
2.將函數作為實參傳遞給另一個函數調用
閉包的作用
1.閉包所使用的函數內部的變量在函數執行完后,仍然存活在內存中(延長了局部變量的生命周期)
2.讓函數外部可以操作(讀寫)到函數內部的數據(變量/函數)
問題:
1.函數執行完后,函數內部聲明的局部變量是否還存在?
一般是不存在的,存在於閉包中的變量才可能存在
2.在函數外部能直接訪問函數內部的局部變量嗎?
不能,但是如果有包含這個局部變量的閉包,我們就可以通過閉包讓外部操作它
代碼理解
1.這是上面常見的閉包中的1中的代碼
2.執行fn1將會產生兩個閉包,fn2和fn3
3.第23行如果只有fn1(),是會產生兩個閉包,但產生完就沒了,因為fn2和fn3是局部變量
4.第23行用f保存了fn3函數對象的引用,fn3變量是消失了,但它所指向的這個函數還存在於f中,所以這個閉包還存在
5.第24行代碼並不是說執行了fn3,fn3早沒了,執行的是f,f函數和fn3一樣而已
6.就是因為4中所說的這個閉包的存在,第24行執行結果才會是1,因為fn1的變量a被保存在這個閉包中,也就體現了閉包的作用中的1(訪問到了a),2(a--,操作了a),也體現了問題中的1(a還存在),2(操作了a)
閉包的生命周期
1.產生
在嵌套內部函數定義執行完就產生了(不是在調用時)
2.死亡
在嵌套的內部函數成為垃圾對象時
閉包應用:定義JS模塊
JS模塊
具有特定功能的js文件(特定功能:有些函數,操作一些數據)
將所有的數據和功能都封裝在一個函數內部 (私有的) (要想私有必須放到一個函數中,對象的屬性是直接可見的)
只向外暴露一個包含n個方法的對象或函數
模塊的使用者,只需要通過模塊暴露的對象調用方法來實現對應的功能
代碼1
代碼2
代碼1使用先要執行函數,代碼2使用起來,更直接更方便
閉包的缺點
1.缺點
函數執行完后,函數內的局部變量沒有釋放,占用內存時間會變長
容易造成內存泄露
2.解決
能不用閉包就不用閉包
及時釋放
內存溢出與內存泄漏
1.內存溢出
一種程序運行出現的錯誤
當程序運行需要的內存超過了剩余的內存時,就拋出內存溢出的錯誤
2.內存泄漏
占用的內存沒有及時釋放
內存泄漏積累多了就容易導致內存溢出
常見的內存泄漏:
意外的全局變量(在函數內部定義的全局變量,以為是局部變量)
沒有及時清理的計時器或回調函數
閉包(沒有及時釋放,導致一直占用內存)
測試題
測試題1
測試題2
測試題3
循環遍歷加監聽
點擊三個按鈕分別顯示它是第幾個
1.普通實現
2.利用閉包實現(閉包不釋放是因為閉包被按鈕對象中的onclick屬性引用,按鈕對象是全局變量,在窗口未關閉之前不會被釋放 )
學識淺薄,如有錯誤,懇請斧正,在下不勝感激。