1. JSON.parse(JSON.stringify()) 方法实现深拷贝
优点:
- 简单快捷
缺点:
- 无法处理对象之间的深层次引用
let a = {};
let b = { a };
a.b = b;
let copyObj = JSON.parse(JSON.stringify(a));
console.log(copyObj); // TypeError
- 如果对象含有Map/Set/RegExp/Date等内置类型,会出现丢失数据的问题
let a = {};
let b = new Set();
b.add(123);
a.s = b;
let copyObj = JSON.parse(JSON.stringify(a));
console.log(a); // { s:Set {123} }
console.log(copyObj); // { s: {} } set 丢失。
- 如果数据过大,在解析为对象形式时,内存消耗大。
let jsonObj = JSON.parse(JSON.stringify(obj));
2. ES5简单实现
此方法仍不能解决对象深层次引用和内置类型数据丢失的问题。
function deepClone(origin, target) {
var tar = target || {};
for (var k in origin) {
if (origin.hasOwnProperty(k)) {
if (typeof origin[k] === 'object' && origin[k] !== null) {
tar[k] = Object.prototype.toString(origin[k]) === '[object Array]' ? [] : {};
deepClone(origin[k], tar[k]);
} else {
tar[k] = origin[k];
}
}
}
return tar;
}
3. ES6 实现
通过借助ES6的weakMap
来解决重复对象之间引用的问题。
function deepClone(origin, hashMap = new WeakMap()) {
// 如果是值类型直接返回。
if (origin == undefined || typeof origin !== 'object') {
return origin;
}
// 用于解决内置类型丢失问题
if (origin instanceof Date) {
return new Date(origin);
}
if (origin instanceof RegExp) {
return new RegExp(origin);
}
if (origin instanceof Set) {
return new Set(origin);
}
if (origin instanceof Map) {
return new Map(origin);
}
const hashkey = hashMap.get(origin);
if (hashkey) {
return hashkey;
}
const target = new origin.constructor();
// 相当于 Array.isarray(origin)?[]:{}; / tar[k] = Object.prototype.toString(origin[k]) === '[object Array]' ? [] : {};
hashMap.set(origin, target);
// 针对 symbol类型
const symKeys = Object.getOwnPropertySymbols(origin);
if (symKeys.length > 0) {
symKeys.forEach(s => {
if (typeof origin[s] === 'object' && origin[s] !== null) {
target[s] = deepClone(origin[s]);
} else {
target[s] = origin[s];
}
})
}
for (let k in origin) {
if (origin.hasOwnProperty(k)) {
target[k] = deepClone(origin[k], hashMap);
}
}
return target;
}