使用具備垃圾收集機制語言編寫程序,開發人員一般不必操心內存管理的問題。但是,JavaScript在進行內存管理即垃圾收集時面臨的問題還是有點與衆不同。其中最主要的一個問題,就是分配給Web瀏覽器的可用內存數量通常要比分配給桌面應用程序的少。確保佔有最少的內存可以讓頁面獲得更好的性能,而優化內存佔有最佳方式,就是爲執行的代碼值保存必要的數據。
基本類型值和引用類型值
ECMAScript變量包含兩種不同數據類型的值:基本類型值和引用類型值。基本類型值保存在棧內存中,而引用類型值保存在堆內存中。
5種基本類型Undefined、Null、Boolean、Number、String,它們的值在內存中分別佔有固定大小的空間,因此可以把它們的值保存在棧內存中,也可以提高查詢變量的速度,對於它們可以說是按值訪問的。
如果是引用類型的值,則必須在堆內存中分配空間。因爲它們的值大小不固定,因此不能保存在棧內存中,但內存地址的大小是固定的,所以可以將內存地址保存在棧內存中,再根據地址找到保存在堆中的值,這種查詢方式叫做按引用訪問。
動態屬性
對於引用類型的值,可以爲其添加屬性和方法,也可以改變和刪除其屬性和方法,例如:
var myobj = new Object();
myobj.name = "obj";
alert(myobj.name);
但是不能給基本類型的值添加屬性,例如:
var mystr = "string";
mystr.name = "str";
alert(mystr.name); //undefined
複製變量值
如果從一個變量向另一個變量複製基本類型的值,會在棧中創建一個新值,然後把該值複製到爲新變量分配的位置上,例如:
var num1 = 5;
var num2 = num1;
如果從一個變量向另一個變量複製引用類型的值,同樣會將存儲在棧中的值複製一份放到爲新變量分配的空間中。但是這個值的副本實際是指向存儲在堆中的一個對象的指針,例如:
var myobj1 = new Object();
var myobj2 = myobj1;
myobj1.name = "obj";
alert(myobj2.name); //obj
傳遞參數
ECMAScript中所有函數參數都是按值傳遞的。在向參數傳遞基本類型的值時,被傳遞的值會被複制給一個局部變量,在向參數傳遞引用類型的值時,會把這個值在內存中的地址複製給一個局部變量。
使用基本類型值傳遞參數比較簡單,例如:
function add(num) {
num+= 10;
return num;
}
var number = 20;
var result = add(number);
alert(number); //20
alert(result); //30
如果使用引用類型值則稍複雜,例如:
function setName(obj) {
obj.name = "obj";
}
var myobj = new Object();
setName(myobj);
alert(myobj.name); //obj
但這並不表明局部作用域中修改的對象會在全局作用域中反映出來,對象仍然是按值(內存地址)傳遞的,例如:
function setName(obj) {
obj.name = "obj";
obj= new Object();
obj.name = "new obj";
}
var myobj = new Object();
setName(myobj);
alert(myobj.name); //obj
檢測類型
typeof操作符可以檢測一個變量是哪種基本類型,但在檢測引用類型時,總是返回object。通常我們並不是想知道某個值是對象,而是想知道它是什麼類型的對象,可以使用instanceof操作符,語法如下:
result = variable instanceof constructor
如果變量是給定引用類型的實例,那麼instanceof操作符就會返回true。根據規定,所有引用類型的值都是Object的實例。
環境與作用域
執行環境定義了變量或函數有權訪問的其他數據,每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中。這個對象無法訪問,但解析器會在後臺使用它。全局執行環境是最外圍的一個執行環境,在Web瀏覽器中,全局執行環境被認爲是window對象。某個執行環境中的所有代碼執行完畢後,該環境被銷燬,保存在其中的所有變量和函數定義也隨之銷燬。
當代碼在一個環境中執行時,會創建由變量對象構成的一個作用域鏈,保證對執行環境有權訪問的所有變量和函數的有序訪問。全局執行環境是作用域鏈中的最後一環,標識符解析是沿着作用域鏈一級級搜索,從作用域鏈接前端(當前執行環境)開始,直到找到標識符爲止。
作用域鏈的延長
有些語句可以在作用域鏈的前端臨時增加一個變量對象,該變量對象會在代碼執行後被移除,即當執行流進入下列任何一個語句時,作用域鏈就會得到加長:
try-cache語句的catch塊。
with語句。
塊級作用域
JavaScript沒有塊級作用域,即花括號封閉的代碼塊中定義的變量可以在代碼塊外訪問,例如:
if (true) {
varcolor = "blue";
}
alert(color);
變量聲明
在使用var關鍵字聲明變量時,這個變量將被自動添加到距離最近的可用環境中。如果變量在未經聲明的情況下被初始化,那麼該變量會被自動添加到全局環境。