JavaScript深拷贝与浅拷贝
外观
JavaScript深拷贝与浅拷贝是处理对象复制时的两种核心方式,理解它们的区别对避免数据意外修改至关重要。本文将系统讲解其原理、实现方法及实际应用场景。
基本概念[编辑 | 编辑源代码]
浅拷贝(Shallow Copy)[编辑 | 编辑源代码]
浅拷贝仅复制对象的顶层属性。若属性是基本类型(如number
, string
),则直接复制值;若属性是引用类型(如object
, array
),则复制其内存地址(即共享同一引用)。
深拷贝(Deep Copy)[编辑 | 编辑源代码]
深拷贝会递归复制对象的所有层级,生成一个完全独立的副本,新旧对象互不影响。
实现方式与示例[编辑 | 编辑源代码]
浅拷贝方法[编辑 | 编辑源代码]
1. 展开运算符(...)[编辑 | 编辑源代码]
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
shallowCopy.a = 3; // 修改顶层属性
shallowCopy.b.c = 4; // 修改嵌套属性
console.log(original); // { a: 1, b: { c: 4 } } —— 嵌套对象被影响
console.log(shallowCopy); // { a: 3, b: { c: 4 } }
2. Object.assign()[编辑 | 编辑源代码]
const copy = Object.assign({}, original);
深拷贝方法[编辑 | 编辑源代码]
1. JSON.parse(JSON.stringify())[编辑 | 编辑源代码]
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.b.c = 5;
console.log(original.b.c); // 输出 2 —— 原对象不受影响
- 限制:无法复制函数、
Symbol
、undefined
及循环引用。
2. 递归实现[编辑 | 编辑源代码]
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
const result = Array.isArray(obj) ? [] : {};
hash.set(obj, result);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key], hash);
}
}
return result;
}
数学表达[编辑 | 编辑源代码]
对于对象,其浅拷贝和深拷贝可表示为:
- 浅拷贝:
- 深拷贝:
实际应用场景[编辑 | 编辑源代码]
- 浅拷贝适用场景:配置对象合并、快速创建相似对象(无需隔离嵌套数据)。
- 深拷贝适用场景:状态管理(如Redux)、历史记录功能、避免数据污染。
性能对比[编辑 | 编辑源代码]
方法 | 时间复杂度 | 适用场景 |
---|---|---|
(n为顶层属性数) | 简单对象复制 | ||
(d为嵌套深度) | 无特殊类型的对象 | ||
| 复杂对象(含函数、循环引用) |
常见误区[编辑 | 编辑源代码]
- 误以为
const copy = original
是拷贝(实际是引用赋值)。 - 忽视循环引用导致的栈溢出问题(递归深拷贝需用
WeakMap
处理)。
总结[编辑 | 编辑源代码]
理解深浅拷贝的差异能帮助开发者:
- 避免共享引用导致的数据意外修改
- 根据场景选择合适拷贝策略
- 优化程序性能与内存使用