一、概念
1.1 浅拷贝
浅拷贝就是对原位的拷贝,理解为复制更为准确,对原对象的一个精确复制,如果拷贝的对象中存在引用,则会复制引用的地址。简单的来说,浅拷贝是对原对象的复制,复制了一个变量指向了原变量的地址,原对象的改变,拷贝对象也会发生变化。更简单来说就是,给一个人(原对象)加了个别名(拷贝对象)。
2.2 深拷贝
既然叫深拷贝了,就肯定比浅拷贝稍微厉害点。不像浅拷贝的“只是多个名字”,深拷贝会开辟一片的内存地址,把原对象和引用的对象全部复制过来。简单来说就是,一只羊和一直克隆羊,长的一样,但是是俩个独立的个体。
二、深拷贝实现
// 这就是最简单的深拷贝
const deepCloneObJ = JSON.parse(JSON.stringify(obj));
function deepClone(obj) {
function isClass(o) {
if (o === null) return "Null";
if (o === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8, -1);
}
var result;
var oClass = isClass(obj);
if (oClass === "Object") {
result = {};
} else if (oClass === "Array") {
result = [];
} else {
return obj;
}
for (var key in obj) {
var copy = obj[key];
if (isClass(copy) == "Object") {
result[key] = arguments.callee(copy);//递归调用
} else if (isClass(copy) == "Array") {
result[key] = arguments.callee(copy);
} else {
result[key] = obj[key];
}
}
return result;
}
第二版的深拷贝在大部分的情况下适用,但是出现循环以用的时候则会出现一下错误,爆栈!!!
RangeError: Maximum call stack size exceeded
...
所以需要解决下循环引用的问题,下面就是第三版
const obj = {
a: 1,
b: 2,
c: {
aa: 1,
bb: "2",
cc: true,
dd: [1, 1, 3, 4, 5],
ee: { c4: 3 },
},
d: [1, 2, 3, 4, 5],
e: [{ a1: 1 }, { b2: 2 }, { c3: 3 }],
};
obj.f = obj;
const clone = (c) => {
const isObject = (o) => {
if (o === null || o === undefined) return o;
else return Object.prototype.toString.call(o).slice(8, -1);
};
// WeakMap用来保存已经复制过的object, WeakMap<Object, boolean>
let map = new WeakMap();
const dp = (object) => {
let result;
// 判断当前复制操作时的对象的类型
if (isObject(object) == "Object") result = {};
else if (isObject(object) == "Array") result = [];
// 基础类型则直接返回
else return object;
for (const key in object) {
const keyType = isObject(object[key]);
const copy = object[key];
if(map.get(copy)){
// 如果这个对象已经复制过,则不递归操作
return copy
} else if (keyType == "Object") {
// 当前是对象时候则先缓存
map.set(copy, true)
result[key] = dp(copy);
} else if (keyType == "Array") {
result[key] = dp(copy);
} else {
result[key] = copy;
}
}
return result;
};
const res = dp(c)
return res
};
鸽了很久的第三版今天写完