內存泄漏是指 一些對象我們不在使用它的時候,他任然存在
setTimeout 的第一個參數使用字符串而非函數的話,會引發內存泄漏
閉包使用不當
什麼是閉包(Closure)
簡單講,閉包就是指有權訪問另一個函數作用域中的變量的函數。
它由兩部分構成:函數,以及創建該函數的環境。環境由閉包創建時在作用域中的任何局部變量組成。
這種官方的概念是比較難理解的,在面試的時候說出來也不是很專業,因爲沒辦法有個具體的邏輯。
我個人認爲,理解閉包的關鍵在於:外部函數調用之後其變量對象本應該被銷燬,但閉包的存在使我們仍然可以訪問外部函數的變量對象,這就是閉包的重要概念。
function outer(){
var a=1;
return function(){
return a;
}
}
var b=outer()
console.log(b())
產生一個閉包
創建閉包最常見方式,就是在一個函數內部創建另一個函數。下面例子中的 closure 就是一個閉包:
funciton func(){
var a =1,b = 2;
function closure(){
return a+b;
}
return closure;
}
閉包的作用域鏈包含着他自己的作用域,以及包含它的函數的作用域和全局作用域。
閉包的注意事項
.通常,函數的作用域及其所有變量都會在函數執行結束後被銷燬。但是,在創建了一個閉包以後,這個函數的作用域就會一直保存到閉包不存在爲止。
function makeAdder(x){
return function(y){
return x+y
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(5)); //此處爲10
console.log(add10(10))//此處爲20
//在下面釋放對閉包的引用
addd5=null;
add10=null;
從上述代碼可以看到add5 和 add10 都是閉包。它們共享相同的函數定義,但是保存了不同的環境。在 add5 的環境中,x 爲 5。而在 add10 中,x 則爲 10。最後通過 null 釋放了 add5 和 add10 對閉包的引用。
在javascript中,如果一個對象不再被引用,那麼這個對象就會被垃圾回收機制回收;
如果兩個對象互相引用,而不再被第3者所引用,那麼這兩個互相引用的對象也會被回收。
閉包只能取得包含函數中的任何變量的最後一個值
function arrFunc(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=function(){
}
}
return arr;
}
大家看一下上面這個代碼,arr數組中包含了10個匿名函數,每個匿名函數都能訪問外部函數的變量i,那麼i是多少呢?
當arrFunc執行完畢後,其作用域被銷燬,但它的變量對象仍保存在內存中,得以被匿名訪問,這時i的值爲10。
要想保存在循環過程中每一個i的值,需要在匿名函數外部再套用一個匿名函數,在這個匿名函數中定義另一個變量並且立即執行來保存i的值。
、
下面是結論內存泄漏的一些方法
1、給DOM對象添加的屬性是一個對象的引用。範例:
var MyObject = {};
document.getElementById('myDiv').myProp = MyObject;
解決方法:
在window.onunload事件中寫上: document.getElementById('myDiv').myProp = null;
2、DOM對象與JS對象相互引用。範例:
function Encapsulator(element) {
this.elementReference = element;
element.myProp = this;
}
new Encapsulator(document.getElementById('myDiv'));
解決方法:
在onunload事件中寫上: document.getElementById('myDiv').myProp = null;
3、給DOM對象用attachEvent綁定事件。範例:
function doClick() {}
element.attachEvent("onclick", doClick);
解決方法:
在onunload事件中寫上: element.detachEvent('onclick', doClick);
4、從外到內執行appendChild。這時即使調用removeChild也無法釋放。範例:
var parentDiv = document.createElement("div");
var childDiv = document.createElement("div");
document.body.appendChild(parentDiv);
parentDiv.appendChild(childDiv);
解決方法:
從內到外執行appendChild:
var parentDiv = document.createElement("div");
var childDiv = document.createElement("div");
parentDiv.appendChild(childDiv);
document.body.appendChild(parentDiv);
5、反覆重寫同一個屬性會造成內存大量佔用(但關閉IE後內存會被釋放)。範例:
for(i = 0; i < 5000; i++) {
hostElement.text = "asdfasdfasdf";
}
這種方式相當於定義了5000個屬性!
解決方法:
其實沒什麼解決方法:就是編程的時候儘量避免出現這種情況咯~~