深浅拷贝底层原理以及运用场景

107 阅读2分钟

浅拷贝踩坑

let obj={
name:"张三"hobby:["游泳"]
}
let copy=obj

这是浅拷贝嘛?no 不是 这只是赋值

浅拷贝定义有两点:

1、需要生成一个新的对象(新地址)

2、对属性是引用数据类型的,直接赋值(拷贝地址值)

下面写一些浅拷贝方法

方法一
function shallowCopy(source){
    let obj={};
    for(let key in source){
        obj[key]=source[key];
    }
    return obj
} 


方法二

Object.assign(第一层的是“深拷贝”,深层的是“浅拷贝”)
Object.assign({},source)

方法三

扩展运算符 ... 实现的浅拷
let shallowCopy={...source}


方法四

let allDesc = Object.getOwnPropertyDescriptors(source);
let cloneObj = Object.create(Object.getPrototypeOf(source), allDesc);

深拷贝

 let obj={
   name:"张三",
   hobby:["玩游戏"],
   fn(){
       console.log(this.name);
   },
   time:new Date(),
   reg:new RegExp("\\w+")

 };
 方案一
console.log("@有问题的深拷贝",JSON.parse(JSON.stringify(obj)));
console.log("源对象",obj);

方案二
手写一个递归的深拷贝(初始版)
function deepClone(source){
    if(source === null || typeof source !== "object" || source instanceof Date ||source instanceof RegExp || typeof source ==="number"){
    return source;
    }
    
    let obj=Array.isArray(source)?[]:{};
    for(let key in source){
            if(Object.hasOwnProperty.call(source,key)){
                obj[key]=deepClone(source[key]);
            }
    }
    return obj;
}

上面初始版本会有一个问题????
遇到循环引用时,会失效。
let obj = {
        name: "zs",
      };
let obj1 = {
  name: "obj1",
};
obj2 = {
  name: "obj2",
};
obj.child = obj1;
obj1.child = obj2;
obj2.child = obj;
console.log(obj);
console.log(obj === obj.child.child.child);//true
let res= deepClone(obj)
console.log(res === res.child.child.child);//false

进阶版本
const map =new WeakMap();
function deepClone(source,targer={}){
    if(source === null || typeof source !== "object" || source instanceof Date ||source instanceof RegExp || typeof source ==="number"){
    return source;
    }
    if(map.get(source)){
        return map.get(source);
    }
    let obj = Array.isArray(source)?[]:{};
    let allDesc = Object.getOwnPropertyDescriptors(source);
    let cloneObj = Object.create(Object.getPrototypeOf(source), allDesc);
    //或者使用
    //let cloneObj=Object.assign({},source);
    map.set(source,cloneObj);
    for(let key in cloneObj){
        if(Object.hasOwnProperty.call(cloneObj,key)){
            targer[key]=deepClone(source[key]);
            cloneObj[key]=deepClone(cloneObj[key]);
        }
    }
    return cloneObj;
    
}

实战应用

const map = new WeakMap();
let util = {
        uuid: function (len, radix) {
          var chars = uuidCharts,
            uuid = [],
            i;
          radix = radix || chars.length;
          len = len || 16;
          if (len) {
            // Compact form
            for (i = 0; i < len; i++)
              uuid[i] = chars[0 | (Math.random() * radix)];
          } else {
            // rfc4122, version 4 form
            var r;

            // rfc4122 requires these characters
            uuid[8] = uuid[13] = uuid[18] = uuid[23] = "";
            uuid[14] = "4";

            // Fill in random data.  At i==19 set the high bits of clock sequence as
            // per rfc4122, sec. 4.1.5
            for (i = 0; i < 36; i++) {
              if (!uuid[i]) {
                r = 0 | (Math.random() * 16);
                uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
              }
            }
          }

          return uuid.join("");
        },
        deepClone: function (source, target = {}) {
          if (
            typeof source !== "object" ||
            source instanceof Date ||
            source instanceof RegExp ||
            source === null ||
            typeof source === "number"
          ) {
            return source;
          }
          if (map.get(source)) {
            return map.get(source);
          }
          let obj = Array.isArray(source) ? [] : {};
          // let allDesc = Object.getOwnPropertyDescriptors(source);
          // let cloneObj = Object.create(Object.getPrototypeOf(source), allDesc);
          let cloneObj = Object.assign({},source);
          map.set(source, cloneObj);
          for (const key in cloneObj) {
            if (Object.hasOwnProperty.call(cloneObj, key)) {
              cloneObj[key] = dsf.deepClone(cloneObj[key], target);
              target[key] = dsf.deepClone(source[key], target);
            }
          }
          return cloneObj;
        },
      };
      window.dsf = Object.create(util);
      let copy = {
        http: function () {},
        base64: function () {},
        md: function () {},
      };
      dsf.deepClone(copy, dsf);
      console.log("dsf", dsf);