數(shù)據(jù)類(lèi)型
- ECMAScript變量包含兩種不同類(lèi)型的值:基本類(lèi)型值、引用類(lèi)型值;
- 基本類(lèi)型值:指的是保存在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段;
- 引用類(lèi)型值:指的是那些保存在堆內(nèi)存中的對(duì)象,意思是,變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針指向內(nèi)存堆中實(shí)際的值;
兩種訪問(wèn)方式
- 基本類(lèi)型值:按值訪問(wèn),操作的是他們實(shí)際保存的值;
- 引用類(lèi)型值:按引用訪問(wèn),當(dāng)查詢(xún)時(shí),我們需要先從棧中讀取內(nèi)存地址,然后再順藤摸瓜地找到保存在堆內(nèi)存中的值;
兩種類(lèi)型復(fù)制
基本類(lèi)型變量的復(fù)制:
從一個(gè)變量向一個(gè)變量復(fù)制時(shí),會(huì)在棧中創(chuàng)建一個(gè)新值,然后把值復(fù)制到為新變量分配的位置上,改變?cè)磾?shù)據(jù)不會(huì)影響到新的變量(互不干涉);
引用類(lèi)型變量的復(fù)制:
復(fù)制的是存儲(chǔ)在棧中的指針,將指針復(fù)制到棧中為新變量分配的空間中,而這個(gè)指針副本和原指針執(zhí)行存儲(chǔ)在堆中的同一個(gè)對(duì)象,復(fù)制操作結(jié)束后,兩個(gè)變量實(shí)際上將引用同一個(gè)對(duì)象;因此改變其中的一個(gè),將影響另一個(gè);
函數(shù)參數(shù)的傳遞
1、ECMA中所有函數(shù)的參數(shù)都是按值傳遞的
在向參數(shù)傳遞基本類(lèi)型的值時(shí),被傳遞的值會(huì)被復(fù)制給一個(gè)局部變量,在向參數(shù)傳遞引用類(lèi)型的值時(shí),會(huì)把這個(gè)值在內(nèi)存的地址復(fù)制給一個(gè)局部變量
基本數(shù)據(jù)類(lèi)型傳遞參數(shù)
funciton addTen(num){
num+=10;
return num;
}
var count=20;
var result=addTen(count);
alert(count);//20
alert(resullt);//30
執(zhí)行結(jié)果是:20和30。
在這段代碼中,將變量count
當(dāng)做參數(shù)傳遞給了函數(shù)addTen
,也就是相當(dāng)于將變量count
的值復(fù)制給了函數(shù)addTen
的參數(shù)。這時(shí)addTen
的參數(shù)num
可以看做是函數(shù)內(nèi)部的一個(gè)變量。
在上段代碼中,就相當(dāng)于兩個(gè)基本數(shù)據(jù)類(lèi)型變量之間的值復(fù)制。而基本數(shù)據(jù)類(lèi)型都有自己獨(dú)立的內(nèi)存地址,所以num
和count
是沒(méi)有任何關(guān)系的,他們只是值相等而已,函數(shù)執(zhí)行完畢后,count
的值并沒(méi)有改變。
而函數(shù)外面的result
是被直接賦值的,所以result
的值就是函數(shù)的結(jié)果30。
引用類(lèi)型傳遞參數(shù)
function setName(obj){
obj.name="LSN";
}
var person=new Object();
setName(person);
alert(person.name); // LSN
執(zhí)行結(jié)果是:LSN。
在這段代碼中,函數(shù)setName
的作用是給obj
對(duì)象添加了一個(gè)屬性name
,并給該屬性賦值為"LSN",因?yàn)?code>obj是引用類(lèi)型,所以這里屬于是將引用類(lèi)型person
賦值給了obj
,也就是說(shuō)person
和obj
引用了一個(gè)內(nèi)存地址,所以當(dāng)給obj
新加了屬性name
時(shí),在函數(shù)外面的person
也跟著改變,最后person.name
的結(jié)果為L(zhǎng)SN。
引用類(lèi)型傳遞參數(shù)到底傳的是值還是引用
function setName(obj){
obj.name="ABC";
obj=new Object();
obj.name="BCD";
}
var person=new Object();
setName(person);
alert(person.name); // ABC
執(zhí)行結(jié)果是:ABC。
實(shí)例3與實(shí)例2的區(qū)別是在函數(shù)中又加了2行代碼,在給obj
對(duì)象新加一個(gè)屬性name
并賦值后又將obj
定義成了一個(gè)新的對(duì)象(new Object()
),定義新對(duì)象后又name
賦上新的值“BCD”。
這個(gè)時(shí)候如果是按引用傳遞的話(huà),那么最后person
對(duì)象就會(huì)自動(dòng)修改為指向其name
屬性為"BCD"的新對(duì)象,但最后顯示的卻是“ABC”,這說(shuō)明即使在函數(shù)內(nèi)部修改了參數(shù)的值,但原始的引用還保持不變。
實(shí)際上,當(dāng)在函數(shù)內(nèi)部obj=new Object()
時(shí) 這個(gè)新的obj
就已經(jīng)成為函數(shù)內(nèi)部的局部對(duì)象了,這個(gè)對(duì)象會(huì)在函數(shù)執(zhí)行完畢后自動(dòng)銷(xiāo)毀。
兩種變量類(lèi)型檢測(cè)
- typeof操作符是檢測(cè)基本類(lèi)型的最佳工具;
- 如果變量值是nul或者對(duì)象,typeof 將返回“object”;
- Instanceof用于檢測(cè)引用類(lèi)型,可以檢測(cè)到具體的,它是什么類(lèi)型的實(shí)例;
- 如果變量是給定引用類(lèi)型的實(shí)例,instanceof操作符會(huì)返回true;
補(bǔ)充:基本包裝類(lèi)型(包裝對(duì)象)
先看下以下代碼:
var s1 = "helloworld";
var s2 = s1.substr(4);
上面我們說(shuō)到字符串是基本數(shù)據(jù)類(lèi)型,不應(yīng)該有方法,那為什么這里s1
可以調(diào)用substr()
呢?
ECMAScript還提供了三個(gè)特殊的引用類(lèi)型Boolean
,String
,Number
。我們稱(chēng)這三個(gè)特殊的引用類(lèi)型為基本包裝類(lèi)型,也叫包裝對(duì)象。
也就是說(shuō)當(dāng)讀取string
,boolean
和number
這三個(gè)基本數(shù)據(jù)類(lèi)型的時(shí)候,后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類(lèi)型對(duì)象,從而讓我們能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù).
所以當(dāng)?shù)诙写a訪問(wèn)s1
的時(shí)候,后臺(tái)會(huì)自動(dòng)完成下列操作:
- 創(chuàng)建String類(lèi)型的一個(gè)實(shí)例;
// var s1 = new String("helloworld");
- 在實(shí)例上調(diào)用指定方法;
// var s2 = s1.substr(4);
- 銷(xiāo)毀這個(gè)實(shí)例;
// s1 = null;
正因?yàn)橛械谌竭@個(gè)銷(xiāo)毀的動(dòng)作,所以基本數(shù)據(jù)類(lèi)型不可以添加屬性和方法,這也正是基本裝包類(lèi)型和引用類(lèi)型主要區(qū)別:對(duì)象的生存期。
使用new
操作符創(chuàng)建的引用類(lèi)型的實(shí)例,在執(zhí)行流離開(kāi)當(dāng)前作用域之前都是一直保存在內(nèi)存中。自動(dòng)創(chuàng)建的基本包裝類(lèi)型的對(duì)象,則只存在于一行代碼的執(zhí)行瞬間,然后立即被銷(xiāo)毀。