從 Object 的等號來真正理解變數

變數真的是你想像中的那個變數嗎?

變數儲存的到底是什麼?

如題,因為是筆記向所以就不花太多時間鋪成。所以就開門見山的說了:

變數可以儲存的值有兩種

一種是「東西本身」,一種是「記憶體位址」。

先測試看看你能不能回答出下面的問題:

1
2
3
4
console.log([] === [])
console.log([0] === [0])
console.log({} === {})
console.log({a: 1} === {a: 1})

如果你的回答是:false false false false,那恭喜你,你是對的。

來看看為什麼吧,先讓我們看另外一個例子:

1
2
3
var obj1 = {a: 1}
var obj2 = {a: 1}
console.log(obj1 === obj2)

最後會輸出的結果會是 false

你可能會很疑惑,想說不是應該會像這樣子嗎:

1
2
3
var a = 5
var b = 5
console.log(a === b) // true

明明都是把東西存到變數裡面,為什麼 存的東西不一樣 會有不同的結果?

你可以參考下面兩張圖。

在你儲存數字的時候,其實是這樣子:

var

但你儲存物件的時候,卻是這樣子:

obj

0x010x05 是記憶體位址的編號,我習慣叫它「指標」(在 C 語言裡是這樣稱呼的)

所以理解這兩個差異後,這樣就說得通了。當你寫 obj1 === obj2 時,其實是等於在問「0x01 === 0x05 嗎?」,這種感覺。

當然,0x010x05 顯然是兩個不同的東西。

所以,當變數儲存的東西不是 String、Boolean、Number、undefined、null 時,都是採用物件這種儲存「指標」的方式來存東西。

undefined 跟 null 也是用「放東西」的方式儲存哦,特別做個範例提醒自己:

1
2
3
4
5
6
var a = undefined
var b = undefined
var c = null
var d = null
console.log(a === b) // true
console.log(c === d) // true

什麼是參考值?

不知道你有沒聽過一種說法:物件儲存的是一個參考值

以前我覺得這個說法很抽象,但其實概念很簡單,讓我們看個例子:

1
2
3
4
var obj1 = {a: 1}
var obj2 = obj1
obj2.a = 10
console.log(obj1.a === obj2.a)

如果前面講的東西你有理解的話,應該能猜到這題的結果是 true

一樣來看圖說故事:

pointer

在你做 obj2 = obj1 時,可以想成是 obj2 = 0x01 這個意思,obj2 儲存的這個值就是我們一開始提到的那個「參考值」。

所以 obj2.a = 10 的意思其實是「把 0x01 裡面的 a 改成 10」的意思,這也解釋為什麼 obj1.a === obj2.a 會得到 true,因為改的就是同一個東西。

為了讓你把變數的觀念學好,現在再來考你一題:

1
2
3
4
var obj1 = {a: 1}
var obj2 = obj1
obj2 = {a: 10}
console.log(obj1.a === obj2.a) // true ? false ?

答案是 false

其實在 obj2 = {a: 10} 這行指令被執行之前,obj1 跟 obj2 的關係就跟剛剛畫的圖片是一樣的。

可是當這行指令被執行後,發生了這件事:

reassign

簡單來說,會有這樣的差異是因為「賦值對象」不同的關係:

  • obj2.a = 10 賦值的對象是「0x01 裡面的 a」
  • obj2 = {a: 10}賦值的對象是「obj2」

所以最後才會有這樣不同的結果。

忘了提那個跟 Object 搞曖昧的傢伙(Array)

Array 其實就是物件的一種,不信的話自己 typeof === []

所以它的變數儲存方式就跟物件一模一樣,來看些例子:

1
2
3
4
5
6
var arr1 = [1]
var arr2 = arr1
arr2.push(3)
console.log('arr1: ' + arr1) // arr1: 1,3
console.log('arr2: ' + arr2) // arr2: 1,3
console.log(arr1 === arr2) // true

它的行為就跟前面的圖一樣,我懶得畫了,忘記了可以自己拉回去上面看。

再來一個例子:

1
2
3
4
5
6
7
8
var arr1 = []
var arr2 = arr1
arr2.push(1)
arr2 = [1, 2, 3]
console.log(arr1) // [1]
console.log(arr2) // [1, 2, 3]
console.log(arr1 === arr2) // false

這題也理解的話就沒什麼問題了。

總結

最後總結一下幾個雷點:

  1. 賦值給變數值,要搞清楚它存的是「東西本身」,還是「參考值」?
  2. 對一個變數重新賦值時,要搞清楚你「賦值的對象是誰?」是「變數本身」,還是「參考值裡的東西」
mentor-program-day06 很有趣的位移運算子與位元運算
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×