Javascript傳參考、傳值差異

在 JavaScript 中,「Call by Value(傳值)」與「Call by Reference(傳參考)」是常被提起但容易誤解的觀念,特別是在處理物件與陣列時。


✅ JS 中的參數傳遞:Call by Value 還是 Call by Reference?

🔑 關鍵理解:

👉 JavaScript 中的所有參數傳遞都是「傳值」(Call by Value)!
但當你傳的是參考型別的變數(如物件、陣列),你傳的是「那個記憶體位址的值」,所以看起來像「傳參考」。


🧠 1. Call by Value(傳值)

  • 適用於:原始型別(Primitive types)
  • 傳入函式時,複製的是值本身
  • 在函式內改變變數,不會影響外部變數
1
2
3
4
5
6
7
8
function changeValue(x) {
x = x + 10;
console.log("inside:", x); // 20
}

let a = 10;
changeValue(a);
console.log("outside:", a); // 10 ✅ 不變

🧠 2. Call by Reference(表面上是傳參考)

  • 適用於:參考型別(Object, Array, Function 等)
  • 傳入的是該物件的記憶體參考值(位址)
  • 在函式內修改物件內容會影響外部原始物件
1
2
3
4
5
6
7
function modify(obj) {
obj.name = "Bob"; // 修改原物件內容
}

let person = { name: "Alice" };
modify(person);
console.log(person.name); // Bob ✅ 被改變了

❗ 但是注意:重新賦值無法改變原物件

1
2
3
4
5
6
7
function change(obj) {
obj = { name: "Charlie" }; // 只是換了一個新物件
}

let user = { name: "Alice" };
change(user);
console.log(user.name); // Alice ❗ 沒被改變

🔍 為什麼?
因為 obj = {...} 是在函式內部重新指定一個新的記憶體參考,不會影響原來的參考地址本身


✅ 總結比較表格

類型 傳遞方式 是否可改變原值 說明
原始型別(數字、字串等) Call by Value ❌ 否 傳入函式時複製值,函式內更改不影響外部
參考型別(物件、陣列等) Call by Value(但是傳 reference 的值) ✅ 可以改內容
❌ 不能重新指定
傳的是記憶體位置的值,可改內容,但不能改記憶體位置本身

🧪 題目挑戰(幫助理解)

❓這段程式碼會輸出什麼?

1
2
3
4
5
6
7
8
function update(arr) {
arr.push(4);
arr = [1, 2]; // 這一行有效嗎?
}

const list = [0];
update(list);
console.log(list); // ??

答案

1
[0, 4] ✅

因為 arr.push(4) 是修改原陣列內容(有效)
arr = [1, 2] 是重新指定變數,不會影響外部的 list


📌 總結一句話:

JavaScript 是 Call by Value,但當你傳的是物件或陣列時,你是傳了參考的值,所以函式能改內容但不能換物件本身


最佳實踐

使用情境描述 是否建議拷貝 推薦方式 原因 / 說明
僅讀取物件資料,不會修改 ❌ 不需要 直接傳入 沒有副作用,效能較佳
函式內部會修改第一層資料(但不應影響原始資料) ✅ 建議 淺拷貝{ ...obj } 防止污染原始資料(僅拷貝第一層)
函式內會修改巢狀屬性,如 obj.user.age = 30 ✅ 必須 深拷貝cloneDeep(obj) 避免巢狀結構共用參考,防止原始物件被改變
僅需要物件中部分資料(如一個 key) ✅ 建議 解構取值function({ id }) 只傳入需要的屬性,可避免整包物件傳入、避免意外修改
處理複雜資料、可能有循環結構或特殊型別(如 function) ✅ 建議 lodash.cloneDeep() 或自定函式 避免 JSON.stringify 限制,保留完整資料類型
效能敏感、不希望多餘拷貝,但又需保護資料 ✅ 可選 防變更操作 + 明確文件註記 可避免不必要的拷貝成本,但需確保開發者不誤改資料
需要修改參數,但只希望在函式內有效(不污染外部) ✅ 必須 深拷貝 + 修改副本 保持資料純淨,函式有單一責任,易於除錯與維護

補充

原則一:不確定資料是否會被改,寧可先拷貝

原則二:若資料大且拷貝成本高,須權衡性能與安全

原則三:資料敏感(如設定檔、使用者狀態)務必拷貝