什么是閉包?
閉包就是一個函數,能夠訪問其他函數內部變量的函數
閉包示例代碼
function outer() { var a = '變量1' var inner = function () { console.info(a) } return inner // inner 就是一個閉包函數,因為他能夠訪問到outer函數的作用域 } var inner = outer() // 獲得inner閉包函數 inner() //"變量1"
當程序執行完var inner = outer(),其實outer的執行環境並沒有被銷毀,因為他里面的變量a仍然被被inner的函數作用域鏈所引用,當程序執行完inner(), 這時候,inner和outer的執行環境才會被銷毀調;《JavaScript高級編程》書中建議:由於閉包會攜帶包含它的函數的作用域,因此會比其他函數占用更多內容,過度使用閉包,會導致內存占用過多。
- 基本類型變量(Number 、Boolean、Undefined、String、Null)的值一般都是存在棧內存中,
- 引用類型變量(Array、Object、Function)的值存儲在堆內存中,棧內存存儲對應空間地址
閉包的作用
1.訪問其他函數內部變量
2.保護變量不被內存回收機制回收
3.避免全局變量被污染 方便調用上下文的局部變量 加強封裝性
閉包的缺點
閉包長期占用內存,內存消耗很大,可能導致內存泄露
如何避免閉包引起的內存泄漏
1,在退出函數之前,將不使用的局部變量全部刪除。可以使變量賦值為null;(示例如下)
這段代碼會導致內存泄露 window.onload = function(){ var el = document.getElementById("id"); el.onclick = function(){ alert(el.id); } } 解決方法為 window.onload = function(){ var el = document.getElementById("id"); var id = el.id; //解除循環引用 el.onclick = function(){ alert(id); } el = null; // 將閉包引用的外部函數中活動對象清除 }
2,避免變量的循環賦值和引用。 (示例如上)
循環引用引起的內存泄漏,是因為IE 的bug,循環引用無法自動判斷,所以通過拷貝值,把內外引用脫鈎,這樣就可回收。IE9及其以后已修復。(感謝 貓SirSir 的講解!)
3,利用Jquery釋放自身指定的所有事件處理程序。
由於jQuery考慮到了內存泄漏的潛在危害,所以*它會手動釋放自己指定的所有事件處理程序 *。只要堅持使用jQuery的事件綁定方法,就可以一定程度上避免這種特定的常見原因導致的內存泄漏。
這段代碼會導致內存泄露 $(document).ready(function() { var button = document.getElementById('button-1'); button.onclick = function() { console.log('hello'); return false; }; }); 當指定單擊事件處理程序時,就創建了一個在其封閉的環境中包含button變量的閉包。
而且,現在的button也包含一個指向閉包(onclick屬性自身)的引用。
這樣,就導致了在IE中即使離開當前頁面也不會釋放這個循環。 用jQuery化解引用循環 $(document).ready(function() { var $button = $('#button-1'); $button.click(function(event) { event.preventDefault(); console.log('hello'); }); });