什么是深拷贝
一个引用对象一般来说由两个部分组成:一个具名的Handle,也就是我们所说的声明(如变量)和一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。
方法一:JSON序列化实现深拷贝
JSON.stringfy()
:可以将JavaScript类型转成对应的JSON字符串;JSON.parse()
:可以解析JSON,将其转回对应的JavaScript类型
JSON序列化实现深拷贝的优缺点:
- 如果只是对一个简单对象进行深拷贝,那么使用该方法是很方便的;
- 但根据上面的打印结果可以发现,原obj的方法属性并没有被拷贝到newObj中;
- JSON序列化只能对普通对象进行深拷贝,如果对象中包含函数、undefined、Symbol等类型的值是无能为力的,会直接将其忽略掉;
方法二:自定义函数
一般简单来说我们都会这么写但是 会有循环引用的问题
什么是循环引用:
- 循环引用指两个对象相互强引用了对方,即retain了对方,从而导致两个对象都无法被释放,引发了内存泄漏现象。
- 在开发中很容易出现循环引用,循环引用可能存在于代码的每个角落,会使内存消耗过高,性能变差,也可能会导致程序崩溃。
- 其实就是 A.point = B; B.point = A;
function copy(obj){
let newobj = null;
if(typeof(obj) == 'object' && obj !== null){
newobj = obj instanceof Array? [] : {};
for(var i in obj){
newobj[i] = copy(obj[i])
}
}else{
newobj = obj
}
return newobj;
}
let objF = {
a:1,
}
objF.a = objF
const deepObj=copy(objF);
用 WeakMap() 或者Map()记录下对象中的所有对象,并与新创建的对象一一对应,即记录引用关系
代码:
let s1 = Symbol("aaa")
let s2 = Symbol("bbb")
const obj = {
name: 'byj',
age: 18,
friend: {
name: 'abc',
},
hobbies: ["abc", "cba", "nba"],
// 函数类型
foo: function( ) {
console.log("foo function")
},
// Symbol作为key和value
[s1]: "abc",
s2: s2,
// Set/Map
set: new Set(['aaa', 'bbb', 'ccc']),
map: new Map([
['aaa', 'abc'],
['bbb', 'cba'],
]),
ud:undefined
};
/**
* 深拷贝
* @param {any} obj 要拷贝的数据
* @param {Map| WeekMap} wMap 弱类型引用 放置循环引用
* @returns
*/
function deepClone(obj ,wMap = new WeakMap()){
//function
if(typeof obj==="function"){
return obj
}
//undefined
if(typeof obj==="undefined"){
return undefined
}
// Map
if(obj instanceof Map){
return new Map([...obj])
}
//Set
if(obj instanceof Set){
return new Set([...obj])
}
//Symobl
if(typeof obj==="symbol"){
return Symbol(obj.description);
}
//值类型
if(typeof obj!="object"&&typeof obj!="function"&&obj!=null){
return obj
}
if(wMap.has(obj)){
console.log(wMap)
return wMap.get(obj)
}
const newData=Array.isArray(obj)?[]:{}
wMap.set(obj,newData)
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
newData[key] = deepClone(obj[key],wMap);
}
}
const symbolKeys=Object.getOwnPropertySymbols(obj);
for (const iterator of symbolKeys) {
newData[iterator]=deepClone(obj[iterator],wMap)
}
return newData;
}
function copy(obj){
let newobj = null;
if(typeof(obj) == 'object' && obj !== null){
newobj = obj instanceof Array? [] : {};
for(var i in obj){
newobj[i] = copy(obj[i])
}
}else{
newobj = obj
}
return newobj;
}
function isObject(value) {
const valueType = typeof value
return (value !== null) && (valueType === "object" || valueType === "function")
}
let objF = {
a:1,
}
objF.a = objF
const deepObj=deepClone(obj);
console.log(deepObj)
const deepObj2=deepClone(objF);
console.log(deepObj2)