方法一
let newObj = JSON.parse(JSON.stringify(obj));
方法二
function deepClone (obj, hash = new WeakMap()) {
// null 和 undefined 是不需要拷贝的
if (obj == null) {
return obj
}
if (obj instanceof RegExp) {
return new RegExp(obj)
}
if (obj instanceof Date) {
return new Date(obj)
}
// 函数是不需要拷贝的
if (typeof obj != 'object') return obj
// 避免陷入死循环
if (hash.get(obj)) return hash.get(obj)
let cloneObj = new obj.constructor()
hash.set(obj, cloneObj)
// for-in循环 会遍历当前对象上的属性和__proto__上的属性
for (let key in obj) {
// 不拷贝 对象的__proto__上的属性
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash)
}
}
return cloneObj
}
// 拷贝目标
let obj = {
name: 'myDog',
age: 12,
boo: true,
n: null,
m: undefined,
sy: Symbol('sym'),
big: 10n,
child: {
ele: 'body',
x: 100
},
arr: [10, 20, 30],
reg: /^\d+$/,
fn: function () {
console.log(this.name)
},
time: new Date(),
err: new Error()
}
obj.obj = obj
let n = deepClone(obj)
n.child.ele = 'abc'
console.log(n)
console.log(obj)
控制台结果
写在最后
方法一的弊端
- obj.obj = obj;会导致死循环,栈溢出
- BigInt类型报错:BigInt Uncaught TypeError: Do not know how to serialize a BigInt
- 属性值类型为 symbol/undefined/function 会丢失
- 信息不准确,例如:正则->空对象 Error 对象->空对象 日期对象->字符串 ...