浅拷贝和深拷贝的反模式本质是误以为数据已隔离而实则共享内存,需通过识别风险场景、选对拷贝粒度、加主动验证机制三层防御规避。

浅拷贝和深拷贝的反模式,本质是“误以为数据已隔离,实则仍在共享内存”。规避的关键不是记住哪些写法危险,而是建立三层防御:识别风险场景、选对拷贝粒度、加主动验证机制。
一、别把浅拷贝当深拷贝用
以下操作看似“复制了对象”,但只停在第一层,嵌套引用仍连着原数据:
-
展开运算符:
const copy = { ...obj }或const arrCopy = [...arr] -
Object.assign():
const copy = Object.assign({}, obj) -
数组方法:
arr.slice()、arr.concat()、Array.from(arr)
只要 obj 或 arr 中含对象、数组、Date、RegExp 等引用类型,这些就全是浅拷贝。修改 copy.nested.prop,obj.nested.prop 会同步变。
二、慎用 JSON 方案替代真正深拷贝
JSON.parse(JSON.stringify(obj)) 是高频反模式:它看起来像深拷贝,实则静默丢数据。
- 函数、
undefined、Symbol、BigInt全部消失(函数被忽略,undefined变null) -
Date变成字符串,RegExp变成空对象{} - 循环引用直接报错:
TypeError: Converting circular structure to JSON - 原型链、getter/setter、不可枚举属性全部丢失
仅适用于纯数据对象(无函数、无日期、无 Symbol、无循环),且需提前校验。否则建议换 structuredClone 或 _.cloneDeep。
三、避免在性能敏感路径滥用深拷贝
深拷贝开销大,尤其在高频执行位置会拖慢体验:
- React 的
render函数、useEffect依赖数组、事件回调中调用深拷贝 - 处理上万条记录的列表时,用深拷贝比对全量状态
- 对未清洗的外部数据(如 API 响应含 DOM 节点、函数、循环引用)直接深拷贝
优化方向:
– 用唯一 ID 做 diff,而非深比较整个对象
– 大对象先剥离非必要字段(如移除 __proto__、onXXX 回调)再序列化
– 加运行时保护:if (JSON.stringify(obj).length > 1e6) throw new Error('Too large')
四、不验证等于没拷贝
拷贝后不验证是否真正隔离,是多数线上 Bug 的起点。简单两步自检:
-
改嵌套属性看原对象:
copy.nested.x = 'test'; console.log(original.nested.x)—— 若输出'test',说明仍是浅拷贝 -
查引用地址:
copy.nested === original.nested返回true,即未切断引用链
关键习惯:接收 API 响应、URL 参数、localStorage 数据后,立即深拷贝;表单编辑等快照类操作,默认走深拷贝或至少手动解构重建嵌套层。











