Understand JavaScript #11 傳值和傳參考
本文主要介紹「傳值和傳參考」的概念,這對於 JavaScript 的開發與除錯會很有幫助,如果不知道這些觀念,可能會導致一些很難 Debug 的奇怪問題。
By Value vs. By Reference
- 傳值 (By Value):所有純值
- 傳參考 (By Reference):所有物件(包含函式)
By Value
參考 (Reference) 是指記憶體的位置。
若 a 為純值,當設定 b 等於 a 時,b 與 a 各自會有一個記憶體位置,而在 b 的記憶體位置上存放的純值,就是從 a 那邊複製過去的值。
複製一個值到另一個不同的記憶體位址,這個方式叫做 By Value。
By Reference
當設定 a 為物件時也會參考到一個記憶體位址,當設定 b 等於 a 時,這次變數 b「不會」得到一個新的記憶體位址,而是指向 a 的記憶體位址,並且不會創造或複製出新的物件。
例如:我同時有「大貓」跟「Damao」兩個名字,這兩個名字都指向我這個人(位址),這個方式叫做 By Reference。
實例說明
By Value (Primitives)
純值的 a 與複製的純值 b 都有自己的記憶體位址,所以當我們改變 a,並不會對 b 有任何影響。
1var a = 3; 2var b; 3 4b = a; 5a = 2; 6 7console.log(a); // 2 8console.log(b); // 3 9
By Reference (All Objects, including Functions)
將物件設定給另一個變數時,只是把兩個變數名稱都指向同一個記憶體位址。
所以如果更改了 c 或 d 任何一個的值,都是在更改它們共同指向的那個物件。
1var c = { greeting: 'hi' }; 2var d; 3 4d = c; 5c.greeting = 'hello'; // mutate 6 7console.log(c); // {greeting: "hello"} 8console.log(d); // {greeting: "hello"} 9
By Reference (even as Parameters)
使用函式的「參數」來傳遞物件時,也會是以傳參考 (By Reference) 的方式傳入。
1var c = { greeting: 'hi' }; 2var d; 3d = c; 4 5function changeGreeting(obj) { 6 obj.greeting = 'Hola'; // mutate 7} 8 9changeGreeting(d); 10console.log(c); // {greeting: "Hola"} 11console.log(d); // {greeting: "Hola"} 12
什麼是 Mutate
Mutate 是一個電腦科學家決定的複雜詞彙,它就是改變某件事 (To Change Something) 的意思。
所以我們在 MDN 或是 Stack Overflow 上面看到別人說 "mutate an object" 或是 "mutate a value",就是指「改變它」的意思,單純就是這個字面上的意思。
我們也會看到另一個常出現的詞彙 Immutable,它的意思是不可改變的 (Can't be changed),但這個觀念這裡先不講。
總之像是新增、刪除物件的屬性,或者修改屬性的值,就是在改變物件,也就是 mutated an object。
例外情況:等號運算子
使用等號運算子時,會發生一個 By Reference 的特殊案例。
當等號運算子發現右方的參數 {greeting: 'howdy'}
是一個尚未存在記憶體中的物件時,等號運算子會先建立一個新的記憶體位置給物件,接著放入值。
完成建立物件後,等號運算子再去指向 c,導致 c 的記憶體位址被改變,這時候 c 和 d 就不是指向同一個記憶體位址了。
1// equals operator sets up new memory space (new address) 2var c = { greeting: 'hi' }; 3var d; 4d = c; 5 6console.log(c); // {greeting: "hi"} 7console.log(d); // {greeting: "hi"} 8 9c = { greeting: 'howdy' }; 10console.log(c); // {greeting: "howdy"} 11console.log(d); // {greeting: "hi"} 12
回顧
看完這篇文章,我們到底有什麼收穫呢?藉由本文可以理解到…
- 所有純值都是傳值,所有物件包含函式都是傳參考
- 簡單介紹 Mutate 的意思
- 使用等號運算子時,物件傳參考的例外情況