JS-Pass by sharing

JavaScript 是「傳值」或「傳址」?

前言

在 2018 iT 邦幫忙鐵人賽,看到Kuro大的重新認識 JavaScript 系列文,仔細的閱讀後,紀錄自己觀念不足的部份,也非常推薦給大家觀看此系列文。


「傳值」或「傳址」?

所以我說那個 JavaScript 是「傳值」或「傳址」呢?

在大多數的情況下,基本型別是「傳值」,而物件型別會是「傳址」的方式,但凡事都有例外。

我們來看看下面這個例子:

1
2
3
4
5
6
7
8
var coin1 = { value: 10 };

function changeValue(obj) {
obj = { value: 123 };
}

changeValue(coin1);
console.log(coin1); // ?

猜猜看,經過 changeValue(coin1) 操作後的 coin1 會是什麼?

答案仍是 { value: 10 }

剛剛說過,物件型別會是「傳址」的方式來更新資料,那應該會是 { value: 123 } 才對,為什麼依然不變?

事實上,JavaScript 不屬於單純的傳值或傳址。
更準確一點來說,JavaScript 應該屬於透過 pass by sharing 來傳遞資料。

「傳值」或「傳址」對大多數的開發者來說應該都不陌生,那麼「pass by sharing」又是什麼呢?


Pass by sharing

「Pass by sharing」的特點在於,
function 的參數,如 function changeValue(obj){ … } 中的 obj重新賦值的時候,
外部變數的內容是不會被影響的。

function裡,重新賦值
1
2
3
4
5
6
7
8
var coin1 = { value: 10 };

function changeValue(obj) {
obj = { value: 123 };
}

changeValue(coin1);
console.log(coin1); // 此時 coin1 仍是 { value: 10 }

如果不是重新賦值的情況,則又會回到大家所熟悉的狀況:

function裡,無 重新賦值
1
2
3
4
5
6
7
8
9
var coin1 = { value: 10 };

function changeValue(obj) {
// 僅更新 obj.value,並未重新賦值
obj.value = 123;
}

changeValue(coin1);
console.log(coin1); // 此時 coin1 則會變成 { value: 123 }

Pass by sharing 說明2

用下例說明,
因為 b變數 原本是指向 a變數 的記憶體位置,共用同一個記憶體,
不過當重新給予 null 值時,b變數 就改指向 null 了,
此時 b變數 就不再指向 a變數 的記憶體位置。

完全重新賦值
1
2
3
4
5
6
var a = {name: "Kanboo"};
var b = a; // b變數 指向 a變數的記憶體位置

b = null; // 完全重新賦值

console.log(a); // {name: "Kanboo"}

若不是 完全重新賦值 的話,就跟傳址的狀況一樣。

用 b變數 去更新值
1
2
3
4
5
6
var a = {name: "Kanboo"};
var b = a; // b變數 指向 a變數的記憶體位置

b.name = "Lucas";

console.log(a); // {name: "Lucas"}