基本類型和引用類型
ECMAScript變量包含兩種不同數(shù)據(jù)類型:基本數(shù)據(jù)類型和引用數(shù)據(jù)類型
基本類型:String,Number,Boolean,Null,Undefined這五種,指的是簡單的數(shù)據(jù)段,是按值訪問的,保存在棧內(nèi)存中,可以直接訪問。
引用類型:Object這一種,指的是由多個值構(gòu)成的對象,包括對象,數(shù)組。按引用(指針)訪問,保存在堆內(nèi)存中,不可以直接訪問。
傳遞參數(shù)
訪問變量有按值和按引用兩種方式,但是,參數(shù)只能按值傳遞。
1.在向參數(shù)傳遞基本類型值時,被傳遞的值會被復(fù)制給一個局部變量(即命名參數(shù),或者用ECMAScript中的概念來說,就是arguments對象中的一個元素)。
2.在向參數(shù)傳遞引用類型值時,會把這個值在內(nèi)存中的地址復(fù)制給一個局部變量,因此這個局部變量的變化會反應(yīng)在函數(shù)的外部。
arguments:是類似數(shù)組的一個對象,本身會存在于函數(shù)體內(nèi)部,用于表示傳入的參數(shù),可以用length屬性和arguments[index]等數(shù)組的方法來查找傳入的參數(shù)。arguments在全局環(huán)境中是不存在的,只存在于函數(shù)作用域中。
以下是兩個例子,細細的理解一下。
傳遞基本類型值:
function addTen(num){
num += 10 ;
return num ;
}
var count = 20 ;
var result = addTen(count) ;
console.log(count) ; //20
console.log(result) ; //30
傳遞引用類型值:
function setName(obj){
obj.name = 'zhd'
}
var person = new Object() ;
setName(person)
console.log(person.name) // {name:'zhd'}
不過,有一個很重要的點就是:當(dāng)在函數(shù)內(nèi)部重寫引用類型值時,這個變量就變成了局部變量,函數(shù)執(zhí)行完畢后就會被立即銷毀。看下面這個例子。
function setName(obj){
obj.name = 'zhd'
obj = new Object();
obj.name = 'zy'
}
var person = new Object() ;
setName(person)
console.log(person.name) // {name:'zhd'}
檢測引用類型
result = variable instanceof constructor
instanceof操作符專門用來檢測一個數(shù)據(jù)是否是引用類型,因為typeof檢測Object,Array,RegExp返回的都是object,而檢測Function卻返回的是function,所以用typeof檢測引用類型值不太準確。
如果變量是引用類型的實例,那么instanceof操作符就會返回true。
垃圾收集
首先分析一下函數(shù)中局部函數(shù)的生命周期:
局部變量只在函數(shù)執(zhí)行的過程中存在。在這個過程中,會為局部變量在?;蛘叨褍?nèi)存上分配相應(yīng)的空間,以便存儲他們的值。然后在函數(shù)中使用這些變量,直至函數(shù)執(zhí)行結(jié)束。結(jié)束后,局部變量就沒有存在的必要了,因此可以釋放他們所占用的內(nèi)存以供將來使用。
標記清除
當(dāng)變量進入執(zhí)行環(huán)境,就將這個變量標記為進入環(huán)境。從邏輯上講,永遠不能釋放進入環(huán)境的變量所占用的內(nèi)存,因為只要執(zhí)行流進入相應(yīng)的環(huán)境,就可能會用到他們。而當(dāng)變量離開環(huán)境時,則將起標記為離開環(huán)境。
垃圾收集器在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記,然后,它會去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記。而在此之后再被加上標記的變量將被視為準備刪除的變量,因為環(huán)境中變量已經(jīng)無法訪問到這些變量了,最后,垃圾收集器完成內(nèi)存清除工作。
目前大多數(shù)瀏覽器用的都是標記清除式的垃圾回收策略。
引用計數(shù)
引用計數(shù)的含義就是跟蹤記錄每個值被引用的次數(shù)。當(dāng)聲明了一個變量并將一個引用類型值賦給該變量時,則這個值得引用次數(shù)就是1.如果同一個值又被賦給另一個變量,則該值得引用次數(shù)加1。相反,如果包含對這個值引用的變量又取得了另一個值,則這個值得引用次數(shù)就減1.當(dāng)這個值得引用次數(shù)為0時,則說明沒有辦法再訪問這個值,然后就可以將其占用的內(nèi)存空間收回。
引用計數(shù)有一個問題,就是循環(huán)引用。循環(huán)引用是指,對象A中包含了一個指向?qū)ο驜的指針,同時,對象B中也包含了一個指向?qū)ο驛的引用。具體例子如下。
function problem(){
var obja = new Object();
var objb = new Object();
obja.son = objb;
objb.parent = obja;
}
上面這個例子中,obja和objb通過各自的屬性相互引用,也就是說,這兩個對象的引用次數(shù)都是2。在采用標記清楚策略的實現(xiàn)中,由于函數(shù)執(zhí)行之后,這兩個對象都離開了作用域,因此相互引用不是問題。
但是,在采用引用計數(shù)策略的實現(xiàn)中,當(dāng)函數(shù)執(zhí)行完畢,obja和objb還將繼續(xù)存在,因為他們的引用計數(shù)永遠不會是0。假如這個函數(shù)被多次調(diào)用,會導(dǎo)致大量的內(nèi)存得不到回收。