在試圖弄清這個問題以前,先要理解棧內存、堆內存和預處理。javascript
var num = 12; function fn() { var num = 100; return function () { console.log(num); } } var f = fn(); f();
例1的圖示java
未被佔用的堆內存纔會被銷燬git
因此,正如圖中橢圓形關鍵點中說明的那樣,堆內存xxxfff111被返回給了全局變量f,而全局變量只有在窗口關閉的時候纔會銷燬,所以堆內存xxxfff111將一直被佔用而不會銷燬,定義它的局部做用域A也不會被銷燬。github
var oDiv = document.getElementById("div1"); ~function() { oDiv.onclick = function() { } }();
這段代碼的特色是:私有做用域給DOM元素的事件綁定一個方法。閉包
例2的圖示:函數
正如圖中橢圓形關鍵點所說,標籤對象的屬性裏面會自帶一個onclick的屬性,未被賦值時其值爲null。那麼,在自執行函數執行的時候,其建立的做用域所佔用的堆內存xxxfff111一樣也會被全局的堆內存xxxfff000佔用(這裏要注意,是堆內存佔用堆內存),因此堆內存xxxfff111和棧內存A都不會被銷燬。spa
只須要將例1稍做修改。設計
function fn(){ var num = 100; return function(){ console.log(num); } } fn(); //主要修改在這裏
例3的圖示code
因爲在函數fn中,xxxfff111是被return的,因此棧內存A的預解釋不會處理xxxfff111,它只在fn函數執行的時候纔會生成,而函數fn的棧內存A每次被執行以後都會被銷燬。對象
將例3稍做修改,就變成了延時銷燬的閉包實例。
function fn(){ var num = 100; return function(){ } } fn()(); //這裏到底發生了什麼?實際上是執行了一次fn以後,把返回的子函數有執行了一次,因此在子函數執行的時候,棧內存fn()是不能銷燬的,可是子函數執行完畢後由於沒有被佔用,因此最終fn()仍是會被銷燬的。
例4的圖示:
正如圖中橢圓形關鍵點處所說,fn()()
的意思是在執行完fn()
以後再把返回的值函數執行一遍。所以在子函數執行的時候,堆內存xxxfff111被佔用了,相應的棧內存A也將保留。
可堆內存xxxfff111中保存的子函數在執行完成以後仍是會被銷燬,接着堆內存xxxfff111就做爲未被佔用的堆內存而被銷燬,最終棧內存A也會被銷燬。
因此,棧內存在執行完以後會被保留一段時間,這段時間等於其子函數執行的時間。
參考資料:
JavaScript高級程序設計(第三版)。
我在github
https://github.com/zhuanyongx...