物件傳參考

JavaScript 中,資料的傳遞分為兩種方式:
- 傳值:Call by value 或 Pass by value
- 傳址(傳參考):Call by reference 或 Pass by reference


傳值

JavaScript 中除了物件型別以外都是基本型別,基本型別就是單純的值。
而基本型別是透過「傳值」的方式傳遞資料:

  • Boolean:布林
  • Null:空值
  • Undefined:未定義
  • Number:數字
  • String:字串

假設今天 a 的值是 10,b 又等於 a,如果把 a 重新賦值 100,那 b 的結果會是什麼呢?

1
2
3
4
var a = 10
var b = a
a = 100
console.log(b)

答案是:10。

在電腦裡的世界,可以想像成一個個空間,有 記憶體位置 的空間,也有 儲存值 的空間。
為了方便取用,才有變數的存在,再用變數連結(指向)這些記憶體位置。
而宣告變數賦值,就是把變數的值存進電腦裡專門存值的空間。
所以在傳值的概念裡,兩個變數分別儲存在不同空間,就算其中變數 a 重新賦值,也不會影響原本複製過去的變數 b
Image

傳址

除了基本型別外,其他型別都算物件型別。
物件的定義需要包含 keyvalue,會以「傳址(傳參考)」的方式傳遞資料:

  • Object:物件
  • Array:陣列
  • Function:函式

以下方範例為例,變數 ab 分別是什麼呢?

1
2
3
4
5
var a = { x: 1 }
var b = a
b.x = 2
a.y = 3
console.log(a, b)

答案是:a = { x: 2, y: 3 }b = { x: 2, y: 3 }

因為物件是「傳址」,所以並不會重新賦值,當然也就不會準備新的儲存空間,只會指向原本的位置。當變數的值改變時,原本位置的值也會跟著改變。

Image

1
2
3
4
5
6
var a = { x: 1 } // 儲存值 (1)
var b = a // b 指向 a - 位置 (1)
b.x = 2 // 對 a 的位置賦值
a.y = 3 // a 的指向位置不變,對自己賦值
console.log(a, b)
// a = { x: 2, y: 3 }, b = { x: 2, y: 3 }

再以下方範例為例:
如果用等號再對變數 b 重新賦值,再宣告一個變數 c 指向 b
請問變數 abc 分別是什麼呢?

1
2
3
4
5
6
var a = { x: 1 }
var b = { x: 2 }
var c = b
b = a
a.y = 3
console.log(a, b, c)

答案是:a = { x: 1, y: 3 }b = { x: 1, y: 3 }c = { x: 2 }
雖然有準備新的空間給變數 b,並且讓 c 指向 b,但是後來又把 b 指向 ac 指向的是 b 原本的記憶體位置,所以當變數 a 的內容改變,b 的值也會一起改變。
Image

1
2
3
4
5
6
7
var a = { x: 1 } // 儲存值 (1)
var b = { x: 2 } // 儲存值 (2)
var c = b // c 指向 b - 位置 (2)
b = a // b 指向 a - 位置 (1)
a.y = 3 // a 的指向位置不變,對自己賦值
console.log(a, b, c)
// a = { x: 1, y: 3 , b = { x: 1, y: 3 }, c = { x: 2 }

參考文章