現在我們來談談 by value 以及 by reference
瞭解這個觀念是很重要的
讓你在 debug 時能夠比較順利
先來看看 by value
我們直接來看程式碼:
// by value (primitives)
var a = 3;
var b;
b = a;
變數 a 在記憶體空間裡的值被設值為 3,
先宣告變數 b,但先不指派值給變數 b,
接著我們將變數 a 透過等號(指派)運算子,將變數 a 指派給變數 b,
這會在記憶體空間產生一個新的記憶體空間並將變數 a 在記憶體空間裡的值拷貝給變數 b 的記憶體空間裡的值,
這種特性只適用變數的值是純值(字串、數值、布林、undefined、null),
如果試圖修改變數 a 透過等號(指派)運算子 來設定一個新的值,
程式碼如下:
// by value (primitives)
var a = 3;
var b;
b = a;
a = 2;
console.log(b);
console.log(a);
猜一下 b 跟 a 在 Console 中的結果,
結果如下:
可以看到修改變數 a 的值並不會影響到變數 b,因為他們各自都有自己的記憶體空間,
圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 36 影片截圖
接著我們來看看 by reference
程式碼如下:
// by reference (all object (include function))
var a = { greeting: 'hi' };
var b;
b = a;
我們先將變數 a 透過等號(指派)運算子來將記憶體空間的值設為一個物件,
宣告變數 b 但先不設定值,
接著我將變數 a 透過等號運算子指派給變數 b ,這時變數 a 與變數 b 都會指向(共用)同一個記憶體空間,
這種特性只適用在物件,
我們修改變數 a 的屬性值,
程式碼如下:
// by reference (all object (include function))
var a = { greeting: 'hi' };
var b;
b = a;
a.greeting = 'hello'; // 透過等號(指派)運算子改變(重新指派)物件的屬性值
console.log(a);
console.log(b);
現在變數 a 與變數 b 的屬性 greeting 的值分別是什麼?
我們到 Console 中來看結果:
可以看到現在屬性 greeting 的屬性值已經都變成 hello 了,但我們只有修改變數 a 的 greeting 屬性值,
因為變數 a 與 變數 b 都指向(共用)同一個記憶體空間,
圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 36 影片截圖
如果我們在呼叫函數時將變數 b 當作參數傳入,
在函數內修改物件的屬性值,
程式碼如下:
// by reference(all object (include function))
var a = { greeting: 'hi' };
var b;
b = a;
a.greeting = 'hello'; // 改變物件的屬性值
// by reference(even as parameters)
function changeGreeting(obj) {
obj.greeting = 'Hola';
}
changeGreeting(b);
console.log(a);
console.log(b);
你覺得 變數 a 與 變數 b 的屬性 greeting 分別是什麼?
我們到 Console 中來看:
可以看到現在變數 a 與變數 b 的 greeting 屬性 的屬性值都變成在函數中修改的 Hola,
這也是因為剛才我們說過變數 a 與變數 b 指向(共用)同一個記憶體空間所致
要特別注意的是如果我們透過等號(指派)運算子重新替變數 a 指派另一個新的物件,
情況就會不一樣,
程式碼如下:
// by reference(all object (include function))
var a = { greeting: 'hi' };
var b;
b = a;
a.greeting = 'hello'; // 改變物件的屬性值
// by reference(even as parameters)
function changeGreeting(obj) {
obj.greeting = 'Hola';
}
changeGreeting(b);
// 如果要重新設值的物件與原來的物件不同,等號(指派)運算子會替我們建立新的記憶體空間並設值
a = { greeting: 'howdy' };
console.log(a);
console.log(b);
在 Console 中變數 a 與變數 b 的 greeting 屬性值分別是什麼?
Console 中的結果:
變數 a 現在有了新的記憶體空間並被設值成新的物件,
變數 b 並沒有跟著指向到新的記憶體空間,
這個情況比較特別,因為新的物件還沒有在記憶體空間裡,
所以會新增一個記憶體空間來存放新的物件,
因此在 JavaScript 中純值是 by value 的,物件是 by reference 的。