[JS基础] 深拷贝-循环引用(Map与WeakMap)

1,382 阅读2分钟

目录

  1. [递归] new Map() 做为函数内部变量时 栈溢出
  2. [递归] new Map() 做为函数参数时 解决了循环引用的问题
  3. 递归赋值过程

一、[递归] new Map() 做为函数内部变量时 栈溢出

//使用Map函数
function deepcopy(obj, map = new Map()){
    if(typeof obj !== 'object'){return}
    let res =  Array.isArray(obj) ? [] :{};
    
    if(map.get(obj)){ 
      return map.get(obj); 
    } 
    map.set(obj,res);
    //console.log('map', map);
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            if(typeof obj[key] === 'object'){
                res[key] = deepcopy(obj[key]);
             }else{
                res[key] = obj[key];
             }
        }
    }
    return res;
};

var obj={a:1,b:2}
obj.c=obj
var deepcopyObj2 = deepcopy(obj);
//deepcopyObj2.c.c1=666
console.log(obj,deepcopyObj2);

image.png

二、[递归] new Map() 做为函数参数时 解决了循环引用的问题

使用 WeakMap() 也一样可以

只修改了注释处的两处

function deepcopy(obj, map = new Map()){ // 把函数内变量转为参数使用
    if(typeof obj !== 'object'){return}
    let res =  Array.isArray(obj) ? [] :{};
    
    if(map.get(obj)){ 
      return map.get(obj); 
    } 
    map.set(obj,res);
    //console.log('map', map);
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            if(typeof obj[key] === 'object'){
                res[key] = deepcopy(obj[key],map); // 修改了此处,传入map
             }else{
                res[key] = obj[key];
             }
        }
    }
    return res;
};

var obj={a:1,b:2}
obj.c=obj
var deepcopyObj2 = deepcopy(obj);
console.log(obj,deepcopyObj2);

image.png

三 递归赋值过程

从里到外,深度优先

function deepcopy(obj, map = new Map()){  
    if(typeof obj !== 'object'){return}
    let res =  Array.isArray(obj) ? [] :{};
  
    if(map.get(obj)){ 
      return map.get(obj); 
    } 
    map.set(obj,res);
    
    console.log('map:::', map);
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            if(typeof obj[key] === 'object'){
                res[key] = deepcopy(obj[key],map);
             }else{
                res[key] = obj[key];
             }
        }
    }
    console.log(res);
    return res;
};

var obj={a:1,b:2,c:{},d:{e:{f:{i:{g:3}}}}}
obj.c=obj
var deepcopyObj2 = deepcopy(obj);

image.png

参考

总结

  • [递归] new Map() 做为函数内部变量时 栈溢出的原因? 为何做为参数就可以?
  • 在JS中有一些已经封装好的如数组方法:concat()filter()slice()map()等,在修改数组时,不会修改原来的数组,而是返回一个新的数组。但这并不是真正的深拷贝,当数组中嵌套数组对象时仍为浅拷贝,嵌套数组的改变仍会影响原数组的值