因為javascript有GC存在,所以記憶體空間並不是被我們重視。王立大神說"理解記憶體空間,就是成為大牛的開始"。所以我們很有必要學習和理解記憶體空間。
2.1 基礎資料型別與變數物件
最新的ECMAScript標準定義了7中資料型別,其中就包括6中基本資料與一種引用資料型別(object)
其中基礎資料型別如圖所示:
下面來探討一個問題,有一個很簡單的例子如下所示:
function fn() {
var a1 = 10;
var a2 = 'hello';
var a3 = null;
}複製程式碼
現在需要思考的是當fn()的時候,區域性變數a1它們都儲存在什麼地方?
函式執行時,會建立一個執行環境,這個執行環境叫做執行上下文(Execution Context)。在執行上下文中,會建立一個叫做變數物件(VO)的東西。基礎型別都儲存在這裡了。
變數物件也存在與堆記憶體中,但是由於變數物件有特殊的功能,所以我們還是儘量將它與堆記憶體區別看待。
2.2 引用資料型別與堆記憶體空間
引用資料型別(Object)的值是儲存在堆記憶體中的。但是我們之前也講過,在javascript中,不允許直接操作堆記憶體。所以操作物件時,實際上是操作物件的引用。因此引用資料型別都是按引用訪問的。這裡的引用,可以理解為儲存在變數物件中的一個地址,該地址與堆記憶體中的物件相關聯。
為了更好地理解變數物件與堆記憶體,下面用一個例子與圖解配合講解。
function foo() {
var a1 = 10;
var a2 = 'hello';
var a3 = null;
var b = { m: 20};
var c = [1,2,3];
}複製程式碼
再來重複一次。函式執行時,會建立一個執行環境,我們把這個執行環境稱為執行上下文。在執行上下文中,會建立一個變數物件(VO)。基本資料型別的值往往都儲存在變數物件中。
如下圖所示,當我們想要訪問堆記憶體空間中的引用資料型別時,實際上是通過引用(地址指標)來訪問的。
在前端面試中,我們常常會遇到這樣一個類似的問題。
//demo01.js
var a = 20;
var b = a;
b = 30;
console.log(a); // a ? 這時a的值多少複製程式碼
//demo02.js
var m = { a:10, b:20};
var n = m;
n.a = 15;
//這時m.a的值是多少?複製程式碼
當變數物件中的資料發生複製行為時,新的變數會被分配一個新的值。所以基本資料型別只是複製了一個,而引用資料型別了不光是複製了同一個引用地址,並且指向同一個地方。
2.3 記憶體空間管理
因為GC的存在,使得我們在開發時好像並不用那麼關心記憶體的使用問題,記憶體的分配與回收完全實現了自動管理(但這並不代表他不會洩漏)。陽波大神說:“瞭解記憶體機制有助於自己清晰地認知到自己寫的程式碼在執行過程中都發生了什麼,從而寫出更優秀的程式碼。”
var a = 20;
alert(a + 100);
a = null;複製程式碼
上面的三條語句,分別對應如下三個過程。
1、分配記憶體;
2、使用分配到的記憶體
3、不需要時銷燬記憶體
1與2都好理解。這裡主要講下3.
javascript的垃圾回收主要是依靠"引用"的概念。當一塊記憶體空間中資料能夠被訪問時,垃圾回收器會認為他是能夠“被獲得的”。不能夠被獲得的資料,就會被打上標記,並且被回收記憶體空間,這種方式叫做標記-清除演算法。