JavaScript 深入解析:Copy by Value、Copy by Reference、Shallow Copy、Deep Copy

·

2 min read

// 1️⃣ Copy by Value (值複製)
// 適用於原始型別 (Primitive Types):Number, String, Boolean, Null, Undefined, Symbol, BigInt
let a = 10;
let b = a; // 這裡是值複製,b 獲得 a 的副本
b = 20; // 改變 b 不會影響 a

console.log(a); // 10
console.log(b); // 20

// 2️⃣ Copy by Reference (引用複製)
// 適用於物件 (Objects, Arrays, Functions)
let obj1 = { name: "Alice", age: 25 };
let obj2 = obj1; // obj2 取得 obj1 的參考 (reference)
obj2.age = 30; // 修改 obj2 也會影響 obj1,因為它們指向同一個記憶體位置

console.log(obj1.age); // 30
console.log(obj2.age); // 30

// 3️⃣ Shallow Copy (淺拷貝)
// 只複製物件的第一層,內部的巢狀結構仍然是引用
let obj3 = { name: "Bob", details: { city: "Taipei", zip: 100 } };
let obj4 = { ...obj3 }; // 使用展開運算符 (...) 進行淺拷貝

obj4.name = "Charlie"; // 改變 name 不影響原物件
obj4.details.city = "Kaohsiung"; // 但改變內部的 details.city 會影響 obj3,因為它仍然是引用

console.log(obj3.name); // Bob
console.log(obj4.name); // Charlie
console.log(obj3.details.city); // Kaohsiung (⚠️ 被修改)
console.log(obj4.details.city); // Kaohsiung

// 4️⃣ Deep Copy (深拷貝)
// 完全複製物件,包括所有巢狀結構,確保不共享記憶體位置
// 方法 1: JSON.parse(JSON.stringify(obj))
let obj5 = { name: "David", details: { city: "Tainan", zip: 700 } };
let obj6 = JSON.parse(JSON.stringify(obj5)); // 這樣可以完全複製

obj6.details.city = "Taichung"; // 修改 obj6 的內部物件,不影響 obj5

console.log(obj5.details.city); // Tainan
console.log(obj6.details.city); // Taichung

// 方法 2: 使用 lodash.cloneDeep (需安裝 lodash 套件)
// import _ from 'lodash';
// let obj7 = _.cloneDeep(obj5); // 完全複製

// ✅ 總結
// - **Copy by Value:** 只適用於原始型別 (數字、字串...)
// - **Copy by Reference:** 物件或陣列的變數存的是「記憶體位址」,所以多個變數指向相同的物件
// - **Shallow Copy:** 只複製第一層,內部巢狀物件仍是引用
// - **Deep Copy:** 完整複製,確保巢狀物件不共享記憶體