一、定义
浅拷贝(Shallow Copy)
拷贝的是对象的第一层属性值:
如果属性是基本类型,直接拷贝值;
如果属性是引用类型(如对象、数组、函数),拷贝的是引用地址,并不会复制内容。
结果:原始对象和新对象共享引用类型属性。
深拷贝(Deep Copy)
递归地拷贝对象的所有层级属性:
不论是基本类型还是引用类型,
最终生成的对象是完全独立的副本,与原对象没有任何共享。
结果:原始对象和新对象完全独立,互不影响。
二、实现方式
1. 浅拷贝实现方式
方法一:Object.assign()
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);
方法二:展开运算符(spread syntax)
const shallowCopy = { ...obj };
方法三:数组用 slice() 或 concat()
const arr = [1, 2, 3];
const newArr = arr.slice(); // 或 arr.concat();
注意:这些方法只复制一层,嵌套对象仍然是引用。
2. 深拷贝实现方式
方法一:JSON.parse(JSON.stringify(obj))【简单、常见】
const deepCopy = JSON.parse(JSON.stringify(obj));
优点:简单直接。
缺点:
会忽略 undefined、function、symbol。
无法处理 Date、RegExp、Map、Set 等特殊类型。
会丢失原型链。
方法二:递归实现
function deepClone(obj, map = new WeakMap()) {
// 原始类型直接返回(包括 BigInt、Symbol、null、undefined、string 等)
if (obj === null || typeof obj !== 'object') return obj;
// 循环引用处理
if (map.has(obj)) return map.get(obj);
// 特殊类型处理
if (obj instanceof Date) return new Date(obj.getTime());
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
if (obj instanceof Error) {
const copy = new obj.constructor(obj.message);
copy.stack = obj.stack;
return copy;
}
// 函数不拷贝,直接返回原始引用(你也可以选择抛错或深克隆 Function)
if (typeof obj === 'function') return obj;
// 保留原型
const result = Array.isArray(obj)
? []
: Object.create(Object.getPrototypeOf(obj));
// 保存到 WeakMap,处理循环引用
map.set(obj, result);
// 拷贝所有属性(包括 Symbol 和不可枚举)
Reflect.ownKeys(obj).forEach((key) => {
const desc = Object.getOwnPropertyDescriptor(obj, key);
if (desc && 'value' in desc) {
desc.value = deepClone(obj[key], map);
}
Object.defineProperty(result, key, desc);
});
return result;
}
方法三:使用 Lodash 的 cloneDeep
npm install lodash
import cloneDeep from 'lodash/cloneDeep';
const deepCopy = cloneDeep(obj);
- 最稳定,支持各种边界情况。
三、实际应用场景
浅拷贝使用场景
- 只操作对象的第一层结构时:
const state = { count: 1 };
const newState = { ...state, count: 2 };
- React/Vue中设置状态或props更新时,常用于不可变数据操作。
深拷贝使用场景
需要完全隔离副本,防止引用污染:
Redux 状态管理中做 immutable 数据更新;
配置数据模板复制;
表单的“还原为初始值”操作;
克隆嵌套数据结构(如嵌套对象或数组);
四、图示理解
const original = {
name: "小明",
info: { age: 26 }
};
const shallow = { ...original };
shallow.info.age = 30;
console.log(original.info.age); // 💥 30(引用被共享)
const deep = JSON.parse(JSON.stringify(original));
deep.info.age = 40;
console.log(original.info.age); // ✅ 30(深拷贝后独立)
五、总结对比表格
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
是否递归 | 否 | 是 |
引用类型共享 | 是(只拷贝引用) | 否(完全复制) |
实现难度 | 简单 | 相对复杂 |
性能 | 快 | 慢(尤其大数据结构) |
适用场景 | 扁平数据结构 | 嵌套结构、需要独立副本时 |