這篇希望能透過一些簡單的範例,讓讀者們能夠輕易了解JavaScript的語言特性。
在JavaScript裡,有多種的資料型別(Data Type),但主要分為兩大類,一類是原始型別(Primitive Type),另一類是物件型別(Object Type)。
String
BigInt
Number
Boolean
Null
Undefined
Symbol( 在 ECMAScript 6 定義)
一般來說,Primitive Type會是pass by value,而Object Type則會是pass by reference,以下會用幾個簡單例子來示範。
首先,要先來了解在電腦的底層世界,想像記憶體空間就像是一個一個的空間,每一個空間都有他的位址,並可以在該空間內儲存值。為了方便取用,才有了「變數」的存在,拿來連結(指向)這些記憶體位址,宣告變數賦值,就是向電腦要一個記憶體空間來儲存值。
var a = ‘jerry’; ,其實是變數 a 指向電腦中某記憶體的位置(ex: 0x01) ,在這個記憶體位置中,儲存 jerry這個值。
如果我再宣告了一個 var b = a; ,雖然 b 和 a 的值一樣都是 ‘jerry’ ,但其實變數 b 是指向了另一個不一樣的記憶體位置 (ex:0x02),把 a 的值 copy 過來存,a 和 b 是存在於兩個獨立不同的記憶體位置中:
在第7行b = ‘tony’;,則是將記憶體位址0x02儲存的值賦予為tony,如下圖 :
var arr1 = [1,2,3]; ,表示 arr1 指向一個新的記憶體位置(ex: 0x01),如果再建立第二個陣列並且讓他等於 arr1: var arr2 = arr1; ,這時 arr2 則會直接指向 arr1 的記憶體位置(0x01),所以不論 arr1 儲存的值為多少, arr2 都會得到一樣的值:
在第3行arr2[0] = 666;,則是將記憶體位址0x01儲存的值index 0 賦予為666,如下圖 :
pass by sharing 的定義就有點像融合了pass by value 和 pass by reference:
碰到原始型別,表現行為是 pass by value。
碰到物件型別,如果只是改變內容,表現行為是 pass by reference,但是如果對物件作重新賦值,表現行為是 pass by value。
所以才會出現這一派的論點,覺得 Javascript 其實是 pass by sharing。
以下的流程分解圖可以更清楚了解物件指向的記憶體位置!
第1~4行
第5行
第6行,改變內容(pass by reference)
第7~10行,重新賦值(pass by value)
第11行
由以上範例可得知,book 在第6行被改變內容(pass by reference),在第7~10行被重新賦值(pass by value),因此bookObj1、bookObj2最終才會有此差異。
結論:在不管名詞定義為何(有些人認為只有pass by sharing),先以行為來分類的話,primitive type基本上是pass by value,而object基本上是 pass by reference,唯一要注意的是重新賦值這個動作造成reference改變所造成的影響。