🌊 一次搞懂前端中的浅拷贝与深拷贝(附实战案例)
在前端开发中,有没有遇到过这种“离谱”的情况:
“我明明复制了一个对象,结果改了副本,原来的也跟着变了!”
这并不是 JavaScript 的 bug,而是你被“浅拷贝”坑了。
别慌——今天我们就用最通俗的语言,一次性搞清楚这些看起来拗口的概念:
深拷贝、浅拷贝、深克隆、浅克隆、深复制、浅复制。
其实,它们都围绕一个核心问题:对象到底是复制值,还是复制引用?
🧠 一、什么是“拷贝”?
在 JS 中,变量分为两大类:
- 基本类型(如 number、string、boolean)
→ 存的是值,复制时也只是把值复制过去。 - 引用类型(如 object、array、function)
→ 存的是“地址”,复制时其实是复制地址。
两个变量指向同一块内存。
所以,如果你修改了其中一个对象的内容,另一个也会被影响。
这就是为什么有时候你“复制了对象”,但改副本时,原来的数据也变了。
💧 二、浅拷贝(Shallow Copy)
✅ 定义
浅拷贝只复制对象的第一层属性。
如果属性的值是对象或数组,那么拷贝的只是“引用地址”。
🧩 举个例子
const obj1 = {
name: "小明",
info: {
age: 18
}
};
const obj2 = { ...obj1 }; // 浅拷贝
obj2.info.age = 20;
console.log(obj1.info.age); // 输出 20 —— 原对象也被改了!
因为 obj2.info 和 obj1.info 指向同一块内存空间。
你改了其中一个,另一个当然也会变。
⚙️ 常见浅拷贝方法
Object.assign({}, obj)- 展开语法
{ ...obj } Array.prototype.slice()Array.prototype.concat()
📌 适用场景:
结构简单、数据层级不深的对象或数组。
优点是性能高、速度快;缺点是容易误改原数据。
🔥 三、深拷贝(Deep Copy)
✅ 定义
深拷贝会把对象的所有层级都复制一份,生成一个全新的对象。
修改新对象不会影响原来的数据。
🧩 举个例子
const obj1 = {
name: "小明",
info: {
age: 18
}
};
const obj2 = JSON.parse(JSON.stringify(obj1)); // 深拷贝
obj2.info.age = 20;
console.log(obj1.info.age); // 输出 18 ✅ 原对象没变
⚙️ 常见深拷贝方式
| 方法 | 优点 | 缺点 |
|---|---|---|
JSON.parse(JSON.stringify(obj)) | 简单、通用 | 无法拷贝函数、Symbol、undefined |
structuredClone(obj) | 原生支持、功能强 | 仅现代浏览器支持 |
lodash.cloneDeep(obj) | 稳定、兼容性好 | 需安装第三方库 |
🌟 推荐方式(现代项目)
const newObj = structuredClone(oldObj);
这是浏览器原生支持的深拷贝方案,
既高效又能处理复杂结构(如 Date、Map、Set)。
⚔️ 四、实战案例:浅拷贝踩坑 vs 深拷贝救场
来看一个开发中经常遇到的“真实事故”。
💥 场景:Vue 或 React 状态被意外修改
const students = [
{ name: "小明", age: 18 },
{ name: "小红", age: 17 }
];
// ❌ 浅拷贝数组
const copyStudents = [...students];
copyStudents[0].age = 20;
console.log(students[0].age); // 输出 20 —— 原数据也被改了!
问题出在哪?
因为展开语法 [...] 只拷贝了外层数组,
内部的对象依旧共用引用地址。
这在前端框架中非常危险:
如果你在 Vue 或 React 的状态中这样操作,
可能导致页面错误刷新、状态错乱。
✅ 正确做法:深拷贝来救场
// 推荐方法 1
const deepCopy = structuredClone(students);
// 或者方法 2
const deepCopy = JSON.parse(JSON.stringify(students));
deepCopy[0].age = 20;
console.log(students[0].age); // 输出 18 ✅ 原数据安全
console.log(deepCopy[0].age); // 输出 20 ✅ 新数据独立
这样,深拷贝就彻底解决了“连带修改”的问题。
数据独立、状态安全,前端程序员终于能安心睡觉了 😄。
🔍 实战结论
| 拷贝方式 | 是否影响原始数据 | 推荐场景 |
|---|---|---|
| 浅拷贝 | 会影响原数据 | 简单结构、性能优先 |
| 深拷贝 | 不会影响原数据 | 状态管理、复杂嵌套 |
🧩 五、拷贝、复制、克隆有区别吗?
其实在前端中,这几个词的意思几乎一样。
| 名称 | 英文 | 含义 |
|---|---|---|
| 拷贝 | copy | 复制数据 |
| 复制 | duplicate | 一般语言描述 |
| 克隆 | clone | 程序员更偏爱用的说法 😎 |
真正需要区分的只有两个字:浅 vs 深。
🚀 六、为什么要区分深浅拷贝?
因为这会直接影响到前端应用的稳定性。
在组件状态管理中(如 React 的 useState 或 Vue 的 reactive):
- 如果只是浅拷贝,修改副本会污染原始状态;
- 深拷贝则能保证每一份数据都相互独立。
一句话总结:
深拷贝是“保险”,浅拷贝是“捷径”。
开发中需要根据数据结构和性能需求灵活选择。
📊 七、深浅拷贝对比一览
| 类型 | 拷贝层级 | 是否共享引用 | 常用方法 | 适用场景 |
|---|---|---|---|---|
| 浅拷贝 | 第一层 | 是 | Object.assign、{...obj} | 简单数据、性能优先 |
| 深拷贝 | 所有层级 | 否 | structuredClone、cloneDeep | 状态管理、复杂对象 |
💡 八、一句话总结
- 浅拷贝:只复制一层,里面的对象“合租”;
- 深拷贝:复制到底,里面的对象“买房独住”。
🔁 九、快速回顾
- “拷贝”、“复制”、“克隆”其实是一回事;
- 关键在于是“浅”还是“深”;
- 浅拷贝快但不安全;
- 深拷贝稳但稍慢;
- 推荐使用
structuredClone()。
🌈 十、写在最后
深浅拷贝看似是一个小细节,却是每个前端工程师必须理解的基础。
它直接关系到数据安全、状态管理、组件通信等核心逻辑。
正所谓:
能搞懂拷贝的人,写出的代码更干净、Bug更少。
所以,记住这句话:
该深就深,该浅就浅,复制要有分寸。
作者:CrabXin
时间:2025年10月
标签:前端开发 / JavaScript / 深拷贝 / 浅拷贝