JavaScript語言是一門優秀的腳本語言。其中包含腳本語言的靈活性外還擁有許多高級語言的特性。例如充許構建和實例化一個對象,垃圾回收機制(GC:Garbage Collecation)。通常我們使用new創建對象,GC負責回收對象佔用內存區域。因此瞭解GC,可以加深對javascript垃圾回收機制的理解。
GC在回收內存時,首先會判斷該對象是否被其它對象引用。在確定沒有其它對象引用便釋放該對象內存區域。因此如何確定對象不再被引用是GC的關鍵所在。
<script type="text/javascript"> function aa() { this.rr = "彈窗"; } function bb() { this.rr = "彈窗"; } var b1; function cc() { var a1 = new aa(); b1 = new bb(); return b1; } cc(); alert(b1.rr) </script>
如上代碼中,執行完cc()後a1被回收了,此後我們可以通過b1.rr彈出文字窗口。在一些基礎書籍中解釋爲:a1爲局部變量,b1是全局變量。局部變量執行完後會被GC回收.但不全是這樣,如下代碼:
<script type="text/javascript"> function aa() { this.rr = "彈窗"; } function bb() { this.rr = "彈窗"; } function cc() { var a1 = new aa(); var b1 = new bb(); return b1; } var b1 = cc(); alert(b1.rr); </script>
此時cc函數中的 a1,b1都是局部變量,但仍然會彈出文字窗口。說明b1並沒有被GC回收。因此javascript中局部變量不是所有時候都被GC回收的。
GC回收機制還需要近一步瞭解。在此時引入幾個概念:雙向鏈表,作用域鏈,活動對象(爲了方便理解,簡化了原文的概念[http://softbbs。pconline。com。cn/9497825。html]) , 其中雙向鏈表描述複雜對象的上下層級關係。 作用域鏈與活動對象分別是雙向鏈表中的某個節點。以函數cc爲例變量層級關係爲:
window<=>cc<=>a1<=>rr <=>b1<=>rr
在執行cc()方法時,內存中變量的引用關係如上圖,文字解釋如下:
- cc的活動對象包括a1和b1,其作用域鏈是window
- cc的活動對象包括a1和b1,其作用域鏈是window
- a1的活動對象包括rr,其作用域鏈是cc
- b1的活動對象包括rr,其作用域鏈是cc
執行cc()時,cc的執行環境會創建一個活動對象和一個作用域鏈。其局部變量a1,b1都會掛在cc的活動對象中。當cc()執行完畢後,執行環境會嘗試回收活動對象佔用的內存。但因局部變量b1 通過return b1,爲其增加了一條作用域鏈:window<=>b1<=>rr,所以GC停止對b1回收。因此如果想將一個局部變量/函數提升爲全局的,爲其增加一條作用域鏈就OK了。
同時控制好對象的作用域鏈也變得重要了。因作用域鏈會意外導致GC無法回收目標對象。例如:
<SCRIPT LANGUAGE="JavaScript"> <!-- //貓 function cat(name) { var zhuren ; this.name = name; //設置主人 this.addZhuRen = function(zr){ zhuren = zr; } this.getZhuRen = function(){ return zhuren; } } //主人 function zhuren(name){ this.name = name; } //創建主人: var zr = new zhuren("zhangsan"); //創建貓 var cat1 = new cat("asan"); //設置該貓的主人 cat1.addZhuRen(zr); //釋放主人 zr = null ; //此處還存在對主人對象的引用 alert(cat1.getZhuRen().name) //--> </SCRIPT>