基本型別與引用型別
ECMAScript包含兩個不同類型的值:基本型別值和參考型別值。基本型別值指的是簡單的資料段;引用型別值指由多個值所構成的物件。當我們把變數賦值給變數時,解析器首先要做的就是確認這個值是基本型別值還是引用型別值。
常見的五種基本資料類型是:
Undifined、Null、Boolean、Number和String。這五種基本資料類型可以直接操作保存在變數中的實際值。
看下面範例:
var a = 10; var b = a; b = 20; console.log(a); // 10 var bl = true; var bl1 = bl; bl1 = false; console.log(bl); // true
上面,b取得值是a值的一份拷貝,雖然,兩個變數的值是相等,但是兩個變數保存兩個不同的基本資料型別值。 b只是保存了a複製的一個副本。所以,當b的值改變時,a的值還是10;
下面,兩個Boolean變數bl和bl1也是基本資料類型,同樣保存兩個不同的基本資料據類型值,bl1保存bl複製的一個副本。
下圖示範了這個基本資料型別賦值的過程:
下面看一下引用型資料:
javascript引用資料型別是保存在堆記憶體中的對象,與其它語言不同的是,你不可以直接存取堆記憶體空間中的位置和操作堆記憶體空間。只能透過操作物件的在堆疊記憶體中的參考位址。所以引用型別的數據,在堆疊記憶體中保存的其實是物件在堆疊記憶體中的參考位址。透過這個引用位址可以快速查找到儲存在堆記憶體中的物件。
看下下面的範例:
var obj1 = new Object(); var obj2 = obj1; obj2.name = "我有名字了"; console.log(obj1.name); // 我有名字了
由上面例子,我們宣告了一個引用資料型別變數obj1,並把它賦值給了另外一個引用資料型別變數obj2。當我們obj2加入了一個name屬性並賦值"我有名字了"。 obj1同樣擁有了和obj2一樣的name屬性。說明這兩個引用資料型別變數指向同一個堆記憶體物件。 obj1賦值給obj2,實際上只是把這個堆疊記憶體物件在堆疊記憶體的引用位址複製了一份給了obj2,但它們本質上共同指向了同一個堆疊記憶體物件。
下面我們來示範這個引用資料型別賦值過程:
自然,為obj2添加name屬性,實際上是為堆疊記憶體中的物件添加了name屬性,obj2和obj1在堆疊記憶體中保存的只是堆疊記憶體物件的參考位址,雖然也是拷貝了一份,但指向的對象卻是同一個。故而改變obj2引起了obj1的改變。
一般而言,基本資料型別是有固定數目的位元組組成,這些位元組可以在解析器的較底層進行運算例如Number和Boolean;而引用資料型,可以包含任意數目的屬性和元素,因此它們無法像基本資料類型那樣很容易的操作。由於,引用資料型別的值是會改變的,所以透過跟基本資料型別一樣的值傳遞方式,也就沒什麼意義了,因為會牽涉到大量的記憶體的複製和比較,效率太低。所以引用資料型別是透過引用傳遞方式,實際傳遞的只是物件的一個位址。例如Array和Function因為它們都是特殊的物件所以它都是引用型別。另外,引用型別是可以新增屬性,基本型別雖然也可以加入屬性,也不會報錯,經測試加入完之後卻是無法存取的。
看下面程式碼:
var a = 12; a.name = "myname"; console.log(a.name); // undefined
String一個特殊的基本資料型別
在很多語言中,String是以物件的形式表示的,但在ECMAScript裡沒有沿用這種傳統,String是當作一種基本資料類型,但它是一個比較特殊的基本型別。
看起來好像String應該做為一個引用類型,但實際上它不是,因為它不是物件。那麼看起來它應該是基本資料類型,應該是通值傳遞的方式來操作。
看下面範例:
var stra = "这是一个字符串"; var strb = stra; stra = "这是另外一个字符串"; console.log(strb); // 这是一个字符串
上面例子我們看到,彷彿stra透過值傳遞的方式複製了一份給了strb。當stra改變的時候,strb並沒有改變,似乎我們已經可以下結論,String就是個基本資料型態。
可是,因為String是可以任意長度的,透過值傳遞,一個一個的複製位元組顯示效率依然很低,看起來String也可以當作引用型別。
看下面範例:
var a = "myobject"; a.name = "myname"; console.log(a.name); // undefined
顯示String無法當作一個物件來處理。實際上,javascript裡的String是不可以改變的,javascript也沒有提供任何一個改變字串的方法和語法。
var a = "myobject"; a = a.substring(3,5) console.log(a); // bj
これを行うと、文字列「myobject」は変更されず、別の文字列「bj」を参照するだけであり、「myobject」はリサイクルされることに注意してください。
したがって、String は実際には上記 2 つのデータ型分類に準拠していないと言えます。両者の中間の 2 つの属性を持つ特殊なタイプです。
以上がこの記事の全内容です。皆さんに気に入っていただければ幸いです。