[JavaScript] 環境與內存

1. 內存分配


1.1 基本類型值和引用類型值

ECMAScript變量包含兩種不同數據類型的值:基本類型值和引用類型值。基本類型值保存在棧內存中,而引用類型值保存在堆內存中。

5種基本類型Undefined、Null、Boolean、Number、String,它們的值在內存中分別佔有固定大小的空間,因此可以把它們的值保存在棧內存中,也可以提高查詢變量的速度,對於它們可以說是按值訪問的。

如果是引用類型的值,則必須在堆內存中分配空間。因爲它們的值大小不固定,因此不能保存在棧內存中,但內存地址的大小是固定的,所以可以將內存地址保存在棧內存中,再根據地址找到保存在堆中的值,這種查詢方式叫做按引用訪問。


1.2 動態屬性

對於引用類型的值,可以爲其添加屬性和方法,也可以改變和刪除其屬性和方法,例如:

var myobj = new Object();
myobj.name = "obj";
alert(myobj.name);

但是不能給基本類型的值添加屬性,例如:

var mystr = "string";
mystr.name = "str";
alert(mystr.name); //undefined


1.3 複製變量值

如果從一個變量向另一個變量複製基本類型的值,會在棧中創建一個新值,然後把該值複製到爲新變量分配的位置上,例如:

var num1 = 5;
var num2 = num1;

如果從一個變量向另一個變量複製引用類型的值,同樣會將存儲在棧中的值複製一份放到爲新變量分配的空間中。但是這個值的副本實際是指向存儲在堆中的一個對象的指針,例如:

var myobj1 = new Object();
var myobj2 = myobj1;
myobj1.name = "obj";
alert(myobj2.name); //obj


1.4 傳遞參數

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


1.5 檢測類型

typeof操作符可以檢測一個變量是哪種基本類型,但在檢測引用類型時,總是返回object。通常我們並不是想知道某個值是對象,而是想知道它是什麼類型的對象,可以使用instanceof操作符,語法如下:

result = variable instanceof constructor

如果變量是給定引用類型的實例,那麼instanceof操作符就會返回true。根據規定,所有引用類型的值都是Object的實例。


2. 執行環境


2.1 環境與作用域

執行環境定義了變量或函數有權訪問的其他數據,每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中。這個對象無法訪問,但解析器會在後臺使用它。

全局執行環境是最外圍的一個執行環境,在Web瀏覽器中,全局執行環境被認爲是window對象。某個執行環境中的所有代碼執行完畢後,該環境被銷燬,保存在其中的所有變量和函數定義也隨之銷燬。

當代碼在一個環境中執行時,會創建由變量對象構成的一個作用域鏈,保證對執行環境有權訪問的所有變量和函數的有序訪問。全局執行環境是作用域鏈中的最後一環,標識符解析是沿着作用域鏈一級級搜索,從作用域鏈接前端(當前執行環境)開始,直到找到標識符爲止。


2.2 作用域鏈的延長

有些語句可以在作用域鏈的前端臨時增加一個變量對象,該變量對象會在代碼執行後被移除,即當執行流進入下列任何一個語句時,作用域鏈就會得到加長:

1) try-cache語句的catch塊。

2) with語句。


2.3 塊級作用域

JavaScript沒有塊級作用域,即花括號封閉的代碼塊中定義的變量可以在代碼塊外訪問,例如:

if (true) {
  var color = "blue";
}
alert(color);


2.4 變量聲明

在使用var關鍵字聲明變量時,這個變量將被自動添加到距離最近的可用環境中。如果變量在未經聲明的情況下被初始化,那麼該變量會被自動添加到全局環境。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章