深拷贝:
将一个引用类型赋值给另一个变量时,是将变量的指针指向那个引用类型,一旦其中某一个发生变化,另一个也会发生变化。
深拷贝的目的就是改变其中一个引用类型的值,不会改变另一个
前置知识:
原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中, 将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
const debug = true;
const log = debug ? console.log.bind(console, "*** debug ***") : () => {};
const isArray = function (o) {
return Object.prototype.toString.call(o) === "[object Array]";
};
const isObject = function (o) {
return Object.prototype.toString.call(o) === "[object Object]";
};
// 看这个就行了
function deepClone(obj = {}) {
if (isObject(obj)) {
// 如果是对象
const r = {};
for (let key in obj) {
log("isObject key", key);
if (obj.hasOwnProperty(key)) {
r[key] = deepClone(obj[key]);
}
}
return r;
} else if (isArray(obj)) {
// 如果是数组
const r = [];
const arr = obj;
for (let i = 0; i < arr.length; i++) {
r[i] = arr[i];
}
return r;
} else {
return obj;
}
}
let obj1 = {
age: 20,
name: "lisi",
address: {
city: "beijing",
area: "fengtai",
},
hobby: ["running", "dancing"],
};
const obj2 = deepClone(obj1);
log("obj2", obj2);
// 清晰版
const deepClone = function (value) {
if (isObject(value)) {
let o = {};
const ks = Object.keys(value);
for (let i = 0; i < ks.length; i++) {
let k = ks[i];
let v = value[k];
o[k] = deepClone(v);
}
return o;
} else if (isArray(value)) {
let l = [];
for (let i = 0; i < value.length; i++) {
let e = deepClone(value[i]);
l.push(e);
}
return l;
} else {
return value;
}
};
// 简洁版:
function deepClone3(obj = {}) {
const isObj = isObject(obj);
const isArr = isArray(obj);
if (isObj || isArr) {
// 如果是对象
const r = isObj ? {} : [];
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
r[key] = deepClone3(obj[key]);
}
}
return r;
} else {
return obj;
}
}
查漏补缺:
深拷贝解决循环引用的问题: juejin.cn/post/691651…
应用
let a = { b: 121, c: 232, c: { b: "1212"},}
// let b = deepClone(a)
// b.b = 121212
// console.log("b", b);
// let b = a
function deepClone(obj, hash = new WeakMap()) {
if(typeof obj !== 'object' || obj === null) {
return obj;
}
if(hash.has(obj)) {
return hash.get(hash);
}
let newObj = Array.isArray(obj) ? [...obj] : {...obj};
hash.set(obj, newObj);
Reflect.ownKeys(obj).forEach(key => {
newObj[key] = deepClone(obj[key], hash);
});
return newObj;
}