普通版本(可以处理循环引用):
function deepCopy(obj, hash = new WeakMap()) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
let copy;
if (Array.isArray(obj)) {
copy = [];
hash.set(obj, copy);
for (let i = 0; i < obj.length; i++) {
copy[i] = deepCopy(obj[i], hash);
}
} else {
copy = {};
hash.set(obj, copy);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key], hash);
}
}
}
return copy;
}
处理很多类型:
function deepClone(origin, target = {}, hash = new WeakMap()) {
if (origin === null) return origin; // null || undefined
else if (origin instanceof Date) return new Date(origin);
else if (origin instanceof RegExp) return new RegExp(origin);
else if (typeof origin !== 'object') return origin;
// 解决引用闭环的问题
if (hash.has(origin)) return hash.get(origin);
// Reflect.ownKeys遍历自身所有属性
Reflect.ownKeys(origin).forEach(function (key) {
if (typeof origin[key] === 'object') {
if (origin[key] instanceof Date)
target[key] = new Date(origin[key]);
else if (origin[key] instanceof RegExp)
target[key] = new RegExp(origin[key]);
else if (origin[key] instanceof Set)
target[key] = new Set(origin[key]);
else if (origin[key] instanceof Map)
target[key] = new Map(origin[key]);
else if (Object.prototype.toString.call(origin[key]) === '[object Array]') {
target[key] = deepClone(origin[key], target[key], hash);
}
else if (Object.prototype.toString.call(origin[key]) === '[object Object]') {
hash.set(origin, origin);
target[key] = deepClone(origin[key], target[key], hash);
} else {
target[key] = null;
}
} else if (typeof origin[key] === 'function') {
target[key] = new Function('return ' + origin[key].toString());
}
// 基本数据类型
else {
target[key] = origin[key];
}
});
return target;
}
测试代码
let s1 = Symbol('s1');
let obj = {
a: '100',
b: undefined,
c: null,
d: Symbol(2),
e: /^\d+$/,
f: new Date(),
g: true,
i: new Set([1, 2, 3, 4]),
arr: [10, 20, 30],
school: {
name: 'cherry',
[s1]: 's1'
},
fn: function fn() {
console.log('fn');
}
};
obj.h = obj;
let obj2 = deepClone2(obj);
console.log('obj', obj, 'obj2', obj2);