閉包:閉包理解 常見的閉包 閉包的作用 閉包的生命周期 (閉包應用:定義JS模塊) 閉包的缺點 內存溢出與內存泄漏 測試題 循環遍歷加監聽


閉包理解

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屬性引用,按鈕對象是全局變量,在窗口未關閉之前不會被釋放  )

 

學識淺薄,如有錯誤,懇請斧正,在下不勝感激。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM