一、什么是浅拷贝(Shallow Copy)
浅拷贝:只复制对象的第一层,嵌套对象仍然共享引用。
示例
const obj = {
name: "Tom",
address: {
city: "Beijing"
}
}
const copy = { ...obj }
copy.address.city = "Shanghai"
console.log(obj.address.city) // Shanghai
原因:
obj
├ name
└ address → 指向同一个内存
浅拷贝只复制:
obj.address 的引用
二、什么是深拷贝(Deep Copy)
深拷贝:递归复制对象所有层级,生成完全独立的新对象。
示例
const obj = {
name: "Tom",
address: {
city: "Beijing"
}
}
const copy = deepClone(obj)
copy.address.city = "Shanghai"
console.log(obj.address.city) // Beijing
结构:
obj.address !== copy.address
三、浅拷贝常见实现方式
1 Object.assign
const copy = Object.assign({}, obj)
2 展开运算符
const copy = { ...obj }
3 数组浅拷贝
const arr = [1,2,3]
const copy1 = arr.slice()
const copy2 = arr.concat()
const copy3 = [...arr]
四、深拷贝常见方法
方法1 JSON序列化(最常见)
const copy = JSON.parse(JSON.stringify(obj))
优点:
简单
缺点:
不能拷贝:
function
undefined
Symbol
Date
RegExp
循环引用
示例:
const obj = {
fn: () => {}
}
JSON.parse(JSON.stringify(obj)) // fn丢失
方法2 structuredClone(现代方法 ⭐推荐)
浏览器原生 API
const copy = structuredClone(obj)
优点:
支持
Map
Set
Date
ArrayBuffer
缺点:
旧浏览器不支持
方法3 lodash
使用 Lodash
import _ from "lodash"
const copy = _.cloneDeep(obj)
优点:
稳定
支持复杂对象
方法4 手写深拷贝(面试最爱)
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj
}
const copy = Array.isArray(obj) ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepClone(obj[key])
}
}
return copy
}
五、解决循环引用(高级面试)
如果对象这样:
const obj = {}
obj.self = obj
普通递归会:
无限递归
解决:使用 WeakMap
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== "object") {
return obj
}
if (hash.has(obj)) {
return hash.get(obj)
}
const clone = Array.isArray(obj) ? [] : {}
hash.set(obj, clone)
for (let key in obj) {
clone[key] = deepClone(obj[key], hash)
}
return clone
}
六、浅拷贝 vs 深拷贝总结
| 对比 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 拷贝层级 | 第一层 | 所有层 |
| 引用对象 | 共享 | 独立 |
| 性能 | 快 | 慢 |
| 实现 | 简单 | 复杂 |
七、真实开发怎么选?
一般:
浅拷贝 90%
深拷贝 10%
原因:
React / Vue 都鼓励 不可变数据更新
例如:
setState({
...state,
user: {
...state.user,
name: "Tom"
}
})
八、面试标准回答(背这个)
可以这样回答:
浅拷贝只复制对象的第一层属性,如果属性值是引用类型,则复制的是引用地址,因此修改嵌套对象会影响原对象。
深拷贝会递归复制对象的所有层级,生成一个完全独立的新对象。常见浅拷贝方式有 Object.assign 和展开运算符。
深拷贝可以使用 JSON.parse(JSON.stringify)、structuredClone、lodash 的 cloneDeep,或者手写递归实现,并通过 WeakMap 解决循环引用问题。