既然都是要寫JavaScript的資訊,不免俗的要來 水一篇 好好探討一下傳值還是傳址。
我們都知道我們的資料都是被存放在記憶體裡面的,但這時候我就很好奇為什麼JS 引擎是如何為我們保留記憶體位置的?
在進入by value 和 by reference 的觀念前我們先來看一段簡單的程式:
var a = 3;
var b;
b = a;
a = 2;
console.log("a is " + a);
console.log("b is " + b)
答案會是:
a is 2
b is 3
感覺很直觀,一點都不難啊,不要急我們再往下走:
var c = {greet : "Hello!"};
var d;
d = c;
c.greet = "你好";
console.log(c);
console.log(d);
這個時候結果會變成:
Object {greet : "你好"}
Object {greet : "你好"}
疑?為什麼這裡兩個都會變成剛剛更改的?明明第一個案例a不會引響b,但為什麼第二個案例c會引響d呢?
這就是接下來我們要說明的地方。
當我今天創建的變數a的值是 primitive type 時,a會在記憶體中有自己的位置(0x001),當這時我打上b = a時,b會先有一個自己的記憶體位置(0x002),然後在把a的值放在自己的記憶體裡面。
因此a 和 b 雖然值一樣,但他們存在於兩個不同的記憶體位置,因此並不會乎相干擾影響。
這種情況,我們就稱為 Call By Value,而這種情形會發生在 primitive type 的變數。
當我今天創建的變數a的值是object時,a一樣會在記憶體中有自己的位置(0x001),當這時我打上b = a時,b就會跟之前不一樣,b不會創建一個新的記憶體位置而是指向a的記憶體位置。
因此當 a 的值改變的時候 b 的值也會改變,因為它們實際上是指稱到相同的位置。
這種情形我們就稱為 Call By Reference,這樣情況會發生在 Object 和 Function 這種變數。
一般來說,Primitive type 是 by value,而 Object 和 Function 則是 by reference,但如果只是這樣Call by value & Call by reference就不會引起這麼大的討論跟困惑。
今天如果我們是使用 object literal 的方式指定物件的值,就不是by reference 而是會變成 by Value,如下面範例:
var a = { number: 1 };
var b;
b = a;
console.log(a);
console.log(b);
a = { number: 2 };
console.log(a);
console.log(b);
結果如下:
{ number: 1 }
{ number: 1 }
{ number: 2 }
{ number: 1 }
在這裡,如果我們是用 object literal 的方式去定義 a這個變數,在這種情況底下,因為它並不清楚 a 的內容是已經存在的,所以它會建立一個新的記憶體位置來存放 c 物件裡面的內容。
看完上面的案例後,是不是滿腦困惑,所以既不是 call by value 也不是 call by reference,那這樣應該叫做什麼呢?
看了很多資料,看到一個名詞:call by sharing。
sharing有「共享」的意思,對於Primitive type來說,看起來會很像 by value,對於object來說則會很像 by reference。這也是目前大多數人的結論。
但與其在爭論by value 還是 by reference又或者是 by sharin,我更喜歡huli的結論是:與其由定義來看,不如直接從行為來加以區分,不同種類能夠達成的行為都不一樣。
{numer:1}
這樣子的值)有興趣的朋友可以點進下方的參考資料看原作者的文章
https://blog.techbridge.cc/2018/06/23/javascript-call-by-value-or-reference/