上节课讲了浅拷贝,浅拷贝有个“坑”,如果对象里有子对象,子数组(引用类型),拷贝的是地址,改一个会影响另一个。
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { ...obj1 }; // 浅拷贝
obj1.b.c = 3;
console.log(obj2.b.c); // 3(原对象子属性被改,拷贝对象也变了)
需要修改这个问题的话就需要「深拷贝」来解决。深拷贝的核心是:遇到引用类型(对象 / 数组),不拷贝地址,而是新建一个完全独立的引用类型,把原数据的值完整复制进去—— 最终新、旧对象彻底分离,改任何一个都不影响另一个。
下面看实现深拷贝的几种方法
方法 1:JSON.parse (JSON.stringify (obj))(开发首选,简单粗暴)
let obj1 = {
a: 0,
b: { c: 0 }, // 子对象(引用类型)
d: [1, 2] // 子数组(引用类型)
};
// 深拷贝核心代码
let obj2 = JSON.parse(JSON.stringify(obj1));
//stringify转JSON parse转JS
// 测试:修改原对象的表层和深层属性
obj1.a = 1;
obj1.b.c = 1;
obj1.d.push(3);
console.log(obj1); // {a: 1, b: {c: 1}, d: [1,2,3]}
console.log(obj2); // {a: 0, b: {c: 0}, d: [1,2]}(完全独立,不受影响)
方法 2:手写深拷贝
核心逻辑是「递归 + 浅拷贝」:遍历对象,遇到基本类型直接拷贝,遇到引用类型(对象 / 数组)就递归调用深拷贝,直到所有层级都拷贝完成。
function deepCopy(object) {
// 1. 边界判断:非对象/数组(null、基本类型)直接返回原数据
if (!object || typeof object !== "object") return object;
// 2. 创建新容器:根据原类型新建数组或对象
let newObject = Array.isArray(object) ? [] : {};
// 3. 遍历原对象,只拷贝自身属性(排除原型链)
for (let key in object) {
if (object.hasOwnProperty(key)) {
// 核心:遇到引用类型就递归深拷贝,基本类型直接赋值
newObject[key] = typeof object[key] === "object" ? deepCopy(object[key]) : object[key];
}
}
return newObject;
}
let obj1 = { a: 1, b: { c: 2 }, d: [3,4] };
let obj2 = deepCopy(obj1);
obj1.b.c = 100;
obj1.d.push(5);
console.log(obj2.b.c); // 2(子对象独立)
console.log(obj2.d); // [3,4](子数组独立)—— 基础版生效!