浅拷贝
浅拷贝,就是只拷贝对象的引用,而不深层次的拷贝对象的值,多个对象指向堆内存中的同一对象,任何一个修改都会使得所有对象的值修改,因为它们公用一条数据。
深拷贝
深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突。
深拷贝的实现
JSON.parse(JSON.stringify(xx))
使用弊端:
- 拷贝
Date
对象,会变成string字符串。 - 拷贝
RegExp
、Error
对象,序列化之后会变成空对象。 - 拷贝函数、undefined,序列化之后会丢失。
- 拷贝NaN、Infinity,序列化之后值会变成null。
JSON.stringify
只能序列化可枚举的对象属性,如果对象是由构造函数生成,序列化之后则会丢失对象的constructor
属性。
function Person(name) {
this.name = name;
}
const liai = new Person('liai');
const a = [1, 2, 3]
const b = { arr: a, date: new Date(), reg: /abc/, err: new Error(), fun() { console.log(123) }, un: undefined, NaN: NaN, infinity: Infinity, liai }
const c = JSON.parse(JSON.stringify(b))
console.log(c);
console.log(c.liai.constructor);
console.log(liai.constructor);
Object.assign(target, ...source)
弊端:无法拷贝对象引用。
最终实现
const deepCopy = function (obj, cache = new WeakMap()) {
if (!obj instanceof Object) return obj;
// 返回循环引用
if (cache.has(obj)) {
console.log(cache.get(obj));
console.log('---------');
return cache.get(obj);
}
// 支持函数
if (obj instanceof Function) {
return function () {
return obj.apply(this, arguments);
};
}
// 支持日期
if (obj instanceof Date) return new Date(obj);
// 支持正则
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
const res = Array.isArray(obj) ? [] : {};
cache.set(obj, res);
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = deepCopy(obj[key], cache);
} else {
res[key] = obj[key];
}
});
return res;
};