浅拷贝与深拷贝的本质区别在于是否切断嵌套引用链:浅拷贝仅复制第一层,引用类型共享堆内存,修改嵌套内容会联动原对象;深拷贝递归复制所有层级,为每个引用类型分配新堆内存,完全独立互不影响。

浅拷贝和深拷贝的本质区别,在于对嵌套引用类型的处理方式不同:浅拷贝只复制第一层属性,若该层中存在对象、数组等引用类型,新旧对象仍共享同一块堆内存;深拷贝则递归遍历所有层级,为每一层引用类型都分配新的堆内存地址,确保完全独立。
关键看“嵌套对象是否联动”
最直接的区分方法是动手改一改:
- 创建一个含嵌套对象的数据,例如
const a = { x: 1, y: { z: 2 } }; - 用待测方式拷贝出
b,如const b = { ...a };或const b = JSON.parse(JSON.stringify(a)); - 执行
b.y.z = 99; - 检查
a.y.z的值:
→ 如果也变成99,说明是浅拷贝;
→ 如果仍是2,说明是深拷贝。
底层差异在内存地址是否分离
JavaScript 中,基本类型(string/number/boolean 等)存于栈,赋值即复制值;而引用类型(object/array 等)实际数据存在堆,变量在栈中只存一个指向堆的地址。
- 浅拷贝:新对象的第一层属性被复制,其中基本类型值被“实拷”,引用类型值拷的是地址——所以嵌套对象的地址没变,还是指向原堆位置。
- 深拷贝:不仅新建第一层对象,还为每个嵌套的引用类型重新在堆中开辟空间,并把内容完整搬过去——新旧对象从顶层到底层,没有共用任何堆内存地址。
常见方法对应关系要记清
别只背名字,得知道它们实际干了什么:
-
浅拷贝典型:Object.assign()、扩展运算符(
{...obj}/[...arr])、Array.prototype.slice()、Array.from() —— 全部只处理第一层。 -
深拷贝典型:structuredClone()(现代浏览器原生支持,可处理 Map/Set/Date/RegExp 等)、Lodash 的
cloneDeep();JSON.parse(JSON.stringify())虽常被当深拷贝用,但会丢undefined、function、Symbol,且不支持循环引用和特殊对象,不算真正可靠。











