浅拷贝只复制第一层属性,嵌套引用类型共享内存地址;深拷贝递归复制所有层级,完全独立。常见浅拷贝方法有展开运算符、object.assign()、slice()/concat();json深拷贝有缺陷,手写需处理循环引用,生产推荐structuredclone()或lodash。

因为浅拷贝只复制对象第一层的属性值,对嵌套的引用类型(比如对象、数组)只复制了内存地址,没创建新副本。新旧对象在深层结构上仍指向同一块堆内存,改其中任意一个,另一方自然同步变化。
关键在于“引用地址被共享”
JavaScript 中对象存储在堆内存,变量里存的是指向它的地址。浅拷贝(如 Object.assign()、展开运算符 {...obj})只是把外层属性的值拷过去:基本类型(数字、字符串等)会真正复制一份;但遇到嵌套对象,拷的仍是那个地址——相当于配了一把新钥匙,开的还是原来的门。
- 修改顶层属性(如
name、id)不会影响原对象,因为那是值拷贝 - 修改嵌套属性(如
user.address.city或list[0].title)会穿透到原始堆数据,原对象跟着变
一个典型复现场景
看这段代码:
const data = {
id: 1,
config: { theme: 'dark', fontSize: 14 }
};
const copy = { ...data };
copy.config.theme = 'light';
console.log(data.config.theme); // 输出 'light' —— 原对象被改了
这里 copy.config 和 data.config 是同一个对象实例,copy.config.theme = 'light' 直接操作了堆里的那个 { theme: 'dark', ... }。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
哪些方法属于浅拷贝且有这风险
Object.assign({}, obj)-
{...obj}(对象展开) -
[...arr](数组展开) -
arr.slice()、Array.from(arr)
它们都只处理第一层,遇到子对象、子数组、Date、RegExp 等引用类型,一律不深挖。
怎么避免这种意外修改
如果后续要改嵌套内容,又不想动原始数据,必须用深拷贝:
- 现代推荐:
structuredClone(obj)(支持 Map、Set、Date、RegExp 等,但不支持函数和 undefined) - 兼容老环境:
JSON.parse(JSON.stringify(obj))(简单结构可用,但丢函数、undefined、Symbol、循环引用) - 复杂需求:用
lodash.cloneDeep或手写递归 + WeakMap 处理循环引用
记住一个判断标准:只要你的代码里会出现 newObj.nested.prop = xxx 这类赋值,且不能接受原对象同步变更,那就不能只靠浅拷贝。










