手写JS—深拷贝

什么是深拷贝

一个引用对象一般来说由两个部分组成:一个具名的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)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值