iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 15
0
Modern Web

教練我想學 JavaScript 系列 第 15

Day 15 By Value 與 By Reference

  • 分享至 

  • xImage
  •  

現在我們來談談 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 的。


上一篇
Day 14 函數就是物件
下一篇
Day 16 物件、函數與「this」
系列文
教練我想學 JavaScript 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言