JS 浅拷贝与深拷贝详解
一、基本概念
浅拷贝:只拷贝对象的第一层属性,深层属性仍然是引用
深拷贝:完全拷贝整个对象,包括所有嵌套对象,新旧对象完全独立
二、浅拷贝的实现方式
1. 扩展运算符
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { ...obj1 };
obj2.b.c = 3;
console.log(obj1.b.c); // 3 (共享引用)
2. Object.assign()
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = Object.assign({}, obj1);
三、深拷贝的实现方式
1. JSON 方法(最简单,但有局限)
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = JSON.parse(JSON.stringify(obj1));
// 缺点:不支持函数、undefined、Symbol、循环引用、Date等特殊对象
2. 递归实现
function simpleDeepCopy(obj) {
// 如果是基本类型,直接返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 如果是数组
if (Array.isArray(obj)) {
return obj.map(item => simpleDeepCopy(item));
}
// 如果是对象
let newObj = {};
for (let key in obj) {
newObj[key] = simpleDeepCopy(obj[key]);
}
return newObj;
}
// 使用示例
let original = {
a: 1,
b: { c: 2 },
d: [1, 2, { e: 3 }]
};
let copied = simpleDeepCopy(original);
copied.b.c = 999;
copied.d[2].e = 888;
console.log(original.b.c); // 2 - 没变 ✓
console.log(original.d[2].e); // 3 - 没变 ✓
四、使用场景与选择建议
使用浅拷贝的场景:
- 数据对象层级简单,没有嵌套对象
- 需要共享部分数据引用
- 性能要求较高
使用深拷贝的场景:
- 需要完全独立的数据副本
- 数据修改不影响原对象
- 处理复杂嵌套结构
最推荐的方法
// 记住这个例子就够了:
let source = { a: 1, b: { c: 2 } };
// ❌ 这样不行(共享所有)
let wrong = source;
// ⚠️ 这样有风险(共享深层)
let shallow = { ...source };
// ✅ 这样安全(完全独立)
let deep1 = JSON.parse(JSON.stringify(source)); // 简单场景
let deep2 = structuredClone(source); // 现代方案 最佳方案(ES2022+)
let deep3 = _.cloneDeep(source); // Lodash方案 兼容性好的方案