一、基本類型和引用類型
ECMAScript 變量可能包含兩種不同數據類型的值:基本類型值和引用類型值。
基本類型值——簡單的數據段:Undefined、Null、Boolean、Number 和String。按值訪問,可以操作保存在變量中的實際的值。
引用類型值——可能由多個值構成的對象。保存在內存中的對象,不允許直接訪問內存中的位置,也就是不能直接操作對象的內存空間。操作對象時,實際上實在操作對象的引用而不是實際的對象,所以,引用類型的值時按引用訪問的。但在為對象添加屬性時,操作的是實際的對象。
1.動態的屬性
只有引用類型能動態地添加屬性,基本類型添加屬性沒有意義。
var person = new Object();
person.name = "Nicholas";
alert(person.name); //"Nicholas"
var name = "Nicholas";
name.age = 27;
alert(name.age); //undefined
2.復制變量值
1)基本類型
直接把值復制到為新變量分配的位置上,兩個變量完全獨立,互不影響。
2)引用類型
將存儲在變量中的值復制一份放到為新變量分配的空間中,但這個值實際上是一個指針,而這個指針指向存儲在隊中的原來的那個對象,也就是復制操作結束后,兩個變量實際上將引用同一個對象。因此,改變其中一個變量,就會影響另一個變量。
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"
3.傳遞參數
ECMAScript 中所有函數的參數都是按值傳遞的。也就是說,把函數外部的值復制給函數內部的參數,就和把值從一個變量復制到另一個變量一樣。
基本類型:
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,沒有變化
alert(result); //30
引用類型:
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
4.檢測類型
tyoeof 操作符——確定一個變量是什么數據類型
var s = "Nicholas";
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object();
alert(typeof s); //string
alert(typeof i); //number
alert(typeof b); //boolean
alert(typeof u); //undefined
alert(typeof n); //object
alert(typeof o); //object
instanceof 操作符——確定一個變量是什么類型的對象
result = variable instanceof constructor
如果變量是給定引用類型(根據它的原型鏈來識別)的實例,那么instanceof 操作符就會返回true。請看下面的例子:
alert(person instanceof Object); // 變量person 是Object 嗎?
alert(colors instanceof Array); // 變量colors 是Array 嗎?
alert(pattern instanceof RegExp); // 變量pattern 是RegExp 嗎?
使用instanceof 操作符檢測基本類型的值,則該操作符始終會返回false,因為基本類型不是對象。
二、執行環境及作用域
執行環境(execution context)是JavaScript 中最為重要的一個概念。執行環境定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變量對象(variable object),環境中定義的所有變量和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在后臺使用它。
在Web 瀏覽器中,全局執行環境被認為是window 對象,因此所有全局變量和函數都是作為window 對象的屬性和方法創建的。某個執行環境中的所有代碼執行完畢后,該環境被銷毀,保存在其中的所有變量和函數定義也隨之銷毀(全局執行環境直到應用程序退出——例如關閉網頁或瀏覽器時才會被銷毀)。
每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行之后,棧將其環境彈出,把控制權返回給之前的執行環境。ECMAScript 程序中的執行流正是由這個方便的機制控制著。
小結:
JavaScript變量可以用來保存基本類型值和引用類型值,他們具有以下特點:
? 基本類型值在內存中占據固定大小的空間,因此被保存在棧內存中;
? 從一個變量向另一個變量復制基本類型的值,會創建這個值的一個副本;
? 引用類型的值是對象,保存在堆內存中;
? 包含引用類型值的變量實際上包含的并不是對象本身,而是一個指向該對象的指針;
? 從一個變量向另一個變量復制引用類型的值,復制的其實是指針,因此兩個變量最終都指向同 一個對象;
? 確定一個值是哪種基本類型可以使用 typeof 操作符,而確定一個值是哪種引用類型可以使用 instanceof 操作符。
所有變量(包括基本類型和引用類型)都存在于一個執行環境(也稱為作用域)當中,這個執行環境決定了變量的生命周期,以及哪一部分代碼可以訪問其中的變量。以下是關于執行環境的幾 點總結:
? 執行環境有全局執行環境(也稱為全局環境)和函數執行環境之分;
? 每次進入一個新執行環境,都會創建一個用于搜索變量和函數的作用域鏈;
? 函數的局部環境不僅有權訪問函數作用域中的變量,而且有權訪問其包含(父)環境,乃至全局環境;
? 全局環境只能訪問在全局環境中定義的變量和函數,而不能直接訪問局部環境中的任何數據;
? 變量的執行環境有助于確定應該何時釋放內存。 JavaScript 是一門具有自動垃圾收集機制的編程語言,開發人員不必關心內存分配和回收問題。可 以對 JavaScript的垃圾收集例程作如下總結。
? 離開作用域的值將被自動標記為可以回收,因此將在垃圾收集期間被刪除。
? “標記清除”是目前主流的垃圾收集算法,這種算法的思想是給當前不使用的值加上標記,然 后再回收其內存。
? 另一種垃圾收集算法是“引用計數”,這種算法的思想是跟蹤記錄所有值被引用的次數。JavaScript 引擎目前都不再使用這種算法;但在 IE中訪問非原生 JavaScript對象(如 DOM元素)時,這種 算法仍然可能會導致問題。
? 當代碼中存在循環引用現象時,“引用計數”算法就會導致問題。
? 解除變量的引用不僅有助于消除循環引用現象,而且對垃圾收集也有好處。為了確保有效地回 收內存,應該及時解除不再使用的全局對象、全局對象屬性以及循環引用變量的引用。