傳值 (Pass by value)
在 JavaScript 中,當變數的值是原生型別時,就是傳值
如果傳遞的變數是原生型別時,傳遞的就會是值的複本,而不是傳遞變數的記憶體位置。我們可以使用 =
來賦予變數一個值舉以下的例子,分別賦予不同數字給 a
、b
:
const a = 1;const b = a + 1;
可以注意到第 2 行,將 b
指定為 a
的值 +1,這時候 c
的值就會是 1 + 1 = 2
,非常直覺也很好理解,這就是所謂的「傳值(Pass by value)」
傳址 (Pass by reference)
在 JavaScript 中,當變數不是原生型別時,就是傳址
當變數是物件或陣列的情況下,JavaScript 會需要額外的紀錄代表其記憶體位置,因此變數內儲存的並不是實際的內容,而是一個內容所在的記憶體位置。舉以下圖表為例,圖表中的 b
變數實際上持存的是記憶體位址:
const a = 1;const b = [1, 2];
變數 | 值 |
---|---|
a | 1 |
b | 0x01 |
記憶體位址 | 值 |
---|---|
0x01 | [1,2] |
了解了傳址的概念後,我們來延伸前面的例子,如果這時候有個變數 c = b
那麼畫成圖表就會是這樣:
const a = 1;const b = [1, 2];const c = b;
變數 | 值 |
---|---|
a | 1 |
b | 0x01 |
c | 0x01 |
記憶體位址 | 值 |
---|---|
0x01 | [1,2] |
如此一來 b
與 c
所指向的記憶體位置都是 0x01
,因此當我們對 c
做修改時,b
也會跟著改變:
let a = 1;let b = [1, 2];let c = b;b.push(3);// 結果:b 與 c 都變成 [ 1, 2, 3 ] 了!
這也是為什麼 b
與 c
的值都會變成 [1, 2, 3]
,因為 b
與 c
都指向了同一個記憶體位置。
相等但不相等
了解前面傳值與傳址的差異後,會發現記憶體位置與值是全然不同的東西,一個是指標,一個是內容,實際就像以下圖表範例。
const a = [1, 2];const b = [1, 2];
console.log(a === b); // false
變數 | 值 |
---|---|
a | 0x01 |
b | 0x02 |
記憶體位址 | 值 |
---|---|
0x01 | [1,2] |
0x02 | [1,2] |
let a = [1, 2];let b = a;console.log(a === b); // true
變數 | 值 |
---|---|
a | 0x01 |
b | 0x01 |
記憶體位址 | 值 |
---|---|
0x01 | [1,2] |
總結
了解 JavaScript 是如何儲存變數有助於更好的操控資料,避免出現改 A 卻動到 B 的狀況。