浅拷贝 vs 深拷贝 - 前端高频面试题
第 10 题:浅拷贝 vs 深拷贝?如何手写深拷贝?
第 10 题:浅拷贝与深拷贝的区别?如何实现深拷贝?
一、浅拷贝(Shallow Copy)
⭐ 定义
只拷贝第一层,遇到引用类型只拷贝引用地址。
也就是说:
- 修改子对象,会影响原对象
- 只复制外壳,不复制内部结构
⭐ 常见浅拷贝方式
javascript
const obj2 = { ...obj1 }
const obj2 = Object.assign({}, obj1)
const arr2 = arr1.slice()
const arr2 = arr1.concat()
二、深拷贝(Deep Copy)
⭐ 定义
完全复制一个新对象,所有嵌套内容都会被复制,不共享引用。
修改副本不会影响原对象。
三、最常见的深拷贝方式:JSON 深拷贝
javascript
let newObj = JSON.parse(JSON.stringify(obj))
✔ 优点
- 简单粗暴好用
- 适合面试聊天开头用
❌ 缺点(必须要说)
- 会丢失
undefined - 会丢失
symbol - 会丢失
function - 无法拷贝
Map/Set - 无法拷贝原型链
- 日期会变成字符串
这段话一定要背熟,面试官听了会点头。
四、真正能用的深拷贝:手写递归版本
面试官: "那你能手写一个深拷贝吗?"
你写下面版本就能给他干沉默。
⭐ 手写深拷贝(可处理循环引用 + 基本类型)
javascript
function deepClone(target, map = new WeakMap()) {
// 基础类型或 null,直接返回
if (typeof target !== 'object' || target === null) {
return target
}
// 处理循环引用
if (map.has(target)) {
return map.get(target)
}
// 处理数组或对象
const clone = Array.isArray(target) ? [] : {}
map.set(target, clone)
for (let key in target) {
if (target.hasOwnProperty(key)) {
clone[key] = deepClone(target[key], map)
}
}
return clone
}
⭐ 可以克隆:
- 对象
- 数组
- 嵌套结构
- 循环引用
❌ 不支持:
- Date
- RegExp
- Map / Set
- Function 的拷贝细节(一般不需要拷贝函数)
但!!面试 95% 情况下够用了。
五、高级版(面试官:嗯?你写得不错啊)
如果你想进一步加分,可以说:
"如果需要完整 deepClone,我会专门写对 Date、RegExp、Map、Set 的处理逻辑。"
如:
javascript
if (target instanceof Date) return new Date(target)
if (target instanceof RegExp) return new RegExp(target)
六、浅拷贝 vs 深拷贝(记忆图表)
| 比较点 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 拷贝层级 | 第一层 | 所有层 |
| 内部对象是否共享? | 共享引用 | 各自独立 |
| 常用方法 | ...、Object.assign |
递归、JSON、第三方库 |
七、速记卡片(背这个就够了)
typescript
📌 浅拷贝:只复制第一层,引用类型共享地址
📌 深拷贝:完全复制,不共享引用
浅拷贝方法:
- {...obj}
- Object.assign()
- slice / concat
JSON 深拷贝:
- 简单但会丢失:undefined / function / symbol / 日期 / 原型 / Map Set
手写深拷贝:
- 递归 + WeakMap 处理循环引用