什么是深拷贝(循环引用)和浅拷贝

一、概念

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
};

鸽了很久的第三版今天写完

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值