基本型別
1 | var a = 10; |
在基本型別時,會認為兩個變數的「值」是相等的,因為兩個變數的「值」都是 10
,同樣的在字串的情況下也是相同的。
1 | var a = 'yswu'; |
因此在基本型別(如string
、number
、boolean
、null
、undefined
),判斷兩個變數是否相等,看的是裡面的內容,也就是裡面的「值」。
繼續來看:
1 | var c = a; |
當 c
指定 a
時,由於 a
是基本型別,所以 c
得到的是 a
的值而不是 a
的記憶體位置,所以儘管 c
改變了 a
也不會受到引響,兩者是獨立的。
當指定(賦值)一個基本型別給變數,就稱作「傳值」(pass by value)。
物件型別
在物件的情況下,先分別宣告兩個物件,兩個物件都有個 value
的屬性。
1 | var obj1 = { value : 10 }; |
可以觀察到,obj1
和 obj2
的屬性和值都相同,得到的卻是false。
這是因為在JavaScript物件,可以把object當作是獨立存在的實體,兩者的記憶體位置並不相同,在比較物件型別時,比較的是記憶體位置,而非值。
繼續來看:將 obj2
利用 obj2 = obj1
的方式來賦值。
1 | var obj1 = { value : 10 }; |
在這邊可以看到,因為 obj1
與 obj2
兩者變數指向相同的記憶體位置,所以 obj1
做修改或新增, obj2
也會跟著改變。
但將 obj1
賦值新的物件時:
1 | obj1 = {}; |
此時因為 obj1
指向新的記憶體位置,而 obj2
還在原來的記憶體位置,因此 obj1
和 obj2
就沒有關係了。
當指定(賦值)一個物件型別給變數,就稱作「傳址」(pass by reference)。
JavaScript 是「傳值」或「傳址」?
在大多數的情況下,基本型別是「傳值」,而物件型別會是「傳址」的方式,但凡事都有例外。
1 | var obj1 = { value: 10 }; |
前面說過物件是利用「傳址」的方式來更新資料,那應該會變成 { value: 999 }
怎麼還是一樣的呢?
事實上,JavaScript 不屬於單純的「pass by value」或「pass by reference」。 更準確一點來說,JavaScript 應該屬於透過 pass by sharing
來傳遞資料。
Pass by sharing
「Pass by sharing」的特點在於,當 function
的參數,如 function changeValue(obj){ ... }
中的 obj
被重新賦值的時候,外部變數的內容是不會被影響的。
如果不是重新賦值的情況,則又會回到大家所熟悉的狀況:
1 | var obj1 = { value: 10 }; |
不少人將 JavaScript 的變數內容傳遞方式,稱為 Pass by sharing:
- 碰到基本型別,表現行為是 Pass by value。
- 碰到物件型別,如果只是對物件內容作操作(例如陣列元素或物件屬性),表現行為是 Pass by reference。
- 碰到物件型別,如果對物件作重新賦值,表現行為是 Pass by value。
或者也有人視為:JavaScript 的基本型別是 Pass by Value,物件型別是 Pass by sharing。