下面是 下一道高频前端面试题(第 17 题:深拷贝与浅拷贝)
继续保持:详细版 + 速记卡片。
✅ 第 17 题:什么是浅拷贝与深拷贝?如何实现深拷贝?
这是前端必考题,答案必须结构化、带例子。
📘 一、浅拷贝(Shallow Copy)
只复制第一层属性,对象内嵌的对象仍然引用同一个地址。
常见浅拷贝方式:
1)Object.assign()
ini
const obj = { a:1, b:{ c:2 } }
const copy = Object.assign({}, obj)
copy.b.c = 999
console.log(obj.b.c) // 999,被影响
2)扩展运算符 ...
go
const copy = { ...obj }
3)Array.prototype.slice / concat
ini
const arr = [1, {x:2}]
const copy = arr.slice()
copy[1].x = 999
console.log(arr[1].x) // 999
结论:浅拷贝只复制第一层,嵌套对象仍共享引用。
📘 二、深拷贝(Deep Copy)
将所有层级的数据复制,不共享引用。
📘 三、深拷贝方法大全
🚀 方法 1:JSON.parse(JSON.stringify())
ini
const obj = { a:1, b:{ c:2 } }
const copy = JSON.parse(JSON.stringify(obj))
👍 优点:简单、常用
⚠️ 缺点:
- 无法拷贝 function
- 无法拷贝 undefined
- 无法拷贝 symbol
- 无法处理循环引用
🚀 方法 2:结构化克隆(现代浏览器最推荐)
ini
const clone = structuredClone(obj)
👍 支持:
- Date / RegExp
- Map / Set
- 深层嵌套
- 循环引用
⚠️ 不支持 function
🚀 方法 3:手写深拷贝(必会面试代码)
go
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (map.has(obj)) return map.get(obj)
const copy = Array.isArray(obj) ? [] : {}
map.set(obj, copy)
for (let key in obj) {
copy[key] = deepClone(obj[key], map)
}
return copy
}
const newObj = deepClone(oldObj)
👍 能力最强:可以处理循环引用 + 深层结构
⚠️ 不处理 function / Symbol 需要额外补强
🚀 方法 4:第三方库 Lodash.cloneDeep
go
const copy = _.cloneDeep(obj)
👍 稳定,功能完备
⚠️ 项目里不一定允许使用
📘 四、浅拷贝 vs 深拷贝 总结表
| 对比点 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 是否复制所有层级? | ❌ 否 | ✅ 是 |
| 是否共享引用? | ✅ 是 | ❌ 否 |
| 常见方法 | Object.assign / ... | JSON / structuredClone / 手写递归 |
| 性能 | 快 | 相对慢 |
| 是否能处理循环引用 | ❌ 否 | structuredClone / 手写可处理 |
📘 五、速记卡片(面试背诵版)
diff
🎯浅拷贝:只复制第一层,嵌套对象共用引用
- Object.assign
- 扩展运算符 ...
- slice / concat
🎯深拷贝:复制所有层级,不共享引用
- JSON.parse(JSON.stringify()) → 快速但有限
- structuredClone() → 最强官方方案
- 手写 deepClone() → 面试必会
- lodash.cloneDeep → 工程可用
核心:深拷贝要解决循环引用 + 各种类型处理
第 18 题将是:防抖(debounce)与节流(throttle)区别与实现。