在JavaScript中,实现深拷贝可以通过递归地复制所有层级的属性来完成。它创建一个新的对象,将一个对象从内存中完整地拷贝出来一份给该新对象,并从堆内存中开辟一个全新的空间存放新对象,且新对象的修改并不会改变原对象,二者实现真正的分离。
使深拷贝函数可以确保你得到一个与原始对象完全独立的副本,不论原始对象的内部结构有多复杂。
function deepClone(target) {
const map = new WeakMap()
function isObject(target) {
return (typeof target === 'object' && target) || typeof target === 'function'
}
function clone(data) {
if (!isObject(data)) {
return data
}
if ([Date, RegExp].includes(data.constructor)) {
return new data.constructor(data)
}
if (typeof data === 'function') {
return new Function('return ' + data.toString())()
}
const exist = map.get(data)
if (exist) {
return exist
}
if (data instanceof Map) {
const result = new Map()
map.set(data, result)
data.forEach((val, key) => {
if (isObject(val)) {
result.set(key, clone(val))
} else {
result.set(key, val)
}
})
return result
}
if (data instanceof Set) {
const result = new Set()
map.set(data, result)
data.forEach(val => {
if (isObject(val)) {
result.add(clone(val))
} else {
result.add(val)
}
})
return result
}
const keys = Reflect.ownKeys(data)
const allDesc = Object.getOwnPropertyDescriptors(data)
const result = Object.create(Object.getPrototypeOf(data), allDesc)
map.set(data, result)
keys.forEach(key => {
const val = data[key]
if (isObject(val)) {
result[key] = clone(val)
} else {
result[key] = val
}
})
return result
}
return clone(target)
}
示例使用:
var original = { a: 1, b: { c: 2 },e:()=>{console.log('hello')} };
var clone = deepClone(original);
console.log(clone === original); // 输出: false
console.log(clone.b === original.b); // 输出: false
基本类型数据
键和值都是基本类型的普通对象
Symbol作为对象的key
Date和RegExp对象类型
Map和Set对象类型
Function对象类型(函数我们一般不用深拷贝)
对象的原型
不可枚举属性
循环引用