基本型別
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。