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