对象拷贝与克隆
约 339 字大约 1 分钟
2026-02-26
对象赋值默认只复制引用地址。要避免互相影响,需要拷贝。
浅拷贝
浅拷贝只复制第一层属性;嵌套对象依然共享引用。
Object.assign
const source = { a: 1, nested: { x: 1 } }
const copy = Object.assign({}, source)
copy.nested.x = 999
console.log(source.nested.x) // 999(说明嵌套引用共享)展开运算符
const source = { a: 1, nested: { x: 1 } }
const copy = { ...source }
copy.nested.x = 999
console.log(source.nested.x) // 999深拷贝
深拷贝会递归复制所有层级,目标是“结构相同但引用不同”。
基础版递归深拷贝
function deepClone(origin) {
if (origin === null || typeof origin !== 'object') {
return origin
}
const target = Array.isArray(origin) ? [] : {}
for (const key in origin) {
if (Object.prototype.hasOwnProperty.call(origin, key)) {
target[key] = deepClone(origin[key])
}
}
return target
}生产可用版(处理循环引用)
function deepClone(origin, cache = new WeakMap()) {
if (origin === null || typeof origin !== 'object') {
return origin
}
if (origin instanceof Date) {
return new Date(origin)
}
if (origin instanceof RegExp) {
return new RegExp(origin)
}
if (cache.has(origin)) {
return cache.get(origin)
}
const target = Array.isArray(origin) ? [] : {}
cache.set(origin, target)
for (const key in origin) {
if (Object.prototype.hasOwnProperty.call(origin, key)) {
target[key] = deepClone(origin[key], cache)
}
}
return target
}JSON 方案与 structuredClone
| 方案 | 优点 | 缺点 |
|---|---|---|
JSON.parse(JSON.stringify(obj)) | 简单、兼容性高 | 丢失 undefined/函数/Symbol/Date/RegExp;无法处理循环引用 |
structuredClone(obj) | 原生深拷贝能力更完整 | 低版本环境可能不支持;函数仍不能拷贝 |
const obj = { a: 1, date: new Date() }
const copy = structuredClone(obj)
console.log(copy)