JavaScript的環境與記憶體

尛沫發表於2014-05-29

使用具備垃圾收集機制語言編寫程式,開發人員一般不必操心記憶體管理的問題。但是,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) {
  var color = "blue";
}
alert(color);

變數宣告

在使用var關鍵字宣告變數時,這個變數將被自動新增到距離最近的可用環境中。如果變數在未經宣告的情況下被初始化,那麼該變數會被自動新增到全域性環境。

本文為Anyforweb技術分享部落格,需要了解網站建設及更多Web應用相關資訊,請訪問anyforweb.com。

相關文章