JavaScript:深浅拷贝

目录

1.什么是深浅拷贝?

2.应用场景

3.自己封装深拷贝工具


1.什么是深浅拷贝?

了解深浅拷贝之前必须要先知道js数据类型和存储方式(基本数据类型储存在栈内存,引用类型储存在堆内存中)。

  1.1 浅拷贝

           是指对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。

例子:

<script>
        var obj={a:1,b:2}
        var tempobj=obj
        console.log(obj)//{a:1,b:2}
        console.log(tempobj)//{a:1,b:2}
        obj.a=111
        console.log(obj.a)//111 
        console.log(tempobj.a)//111   tempobj=obj 就属于浅拷贝
        
</script>

  1.2 深拷贝

          是指拷贝对象的具体内容,二者内存地址是自主分配的,拷贝结束之后俩个对象虽然存的值是一样的,但是内存地址不一样,俩个对象页互相不影响,互不干涉。

总而言之:假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着 变了,说明这是浅拷贝,如果B没变,那就是深拷贝;

2.如何实现深拷贝?

 Array: 

(1)sclice方法:

<script>
        var arr1=[1,2,3]
        arr2 = arr1.slice();
        arr1[0]=111
        console.log(arr1) //[111,2,3]
        console.log(arr2)//[1,2,3]
    </script>

(2)concat

<script>
      var arr10 = [1, 2];
      var arr20 = arr10.concat();
      arr10[0] = "arr1";
      console.log("============");
      console.log(arr10);//['arr1', 2]
      console.log(arr20);//[1, 2]
</script>

数据变为引用类型:

 <script>
      var arr3 = [{ a: 1 }];
      arr4 = arr3.slice();
      arr3[0].a = "arr3";
      console.log(arr3, arr4); // [{ a: arr3 }] [{ a: arr3 }]返回新数组
      var obj5 = { a: 2 };
      var obj6 = Object.create(obj5);
      obj5.a = "obj5";
      console.log(obj5 === obj6); // false
      console.log(obj5.a === obj6.a); // true
</script>

引用类型的时slice concat 都不能深拷贝了,只能实现第一层的深拷贝

 ① JSON内置的方法:

<script>
      var a = { x: 1 };
      var b = JSON.parse(JSON.stringfiy(a));
      console.log(b); //{x:1}
      b.x = 2;
      console.log(b); //{x:2}
      console.log(a); //{x:1}
</script>

 该方法是用JSON.parse将对象转为字符串,然后在用JSON.stringify转回对象json字符串转换为对象的时候,会自己去构建新的内存地址存放数据

注:如果对象属性为function,因为JSON格式字符串不支持function,在构建的时候会自动删除

②Object的内置方法assign:

 <script>
      var a = { x: 1 };
      var b = Object.assign({}, a);
      console.log(b); //{x:1}
      b.x = 2;
      console.log(b); //{x:2}
      console.log(a); //{x:1}
</script>

该方法是用Object.assign对对象进行拼接, 将后续对象的内容插入到第一个参数指定的对象,不会修改第一个参数之后的对象,而我们将第一个对象指定为一个匿名空对象,实现深拷贝

注:对象嵌套层次过深,超过2层,就会出现浅拷贝的状况,比如echarts组件的option对象

3.深拷贝工具

3.1第三方库:lodash under-score

3.2自己封装:

let obj1 = {
  // typeof 数组|对象 => 'object'
  // Array.isArray()
  arr: [1, 2, 3],
  arrayOfObjs: [{ c: 5 }, { d: 6 }],
  date: new Date(),
  object: { val: 4 },
  // 增加一个属性
  fn: function () {
    // typeof fn ===> 'function'
    return 5;
  },
  set: new Set([7, 8, 9, { e: 10 }]),
  map: new Map([
    [11, "f"],
    [12, "g"],
  ]),
  reg: /[h-z]/,
};
console.log(obj1);

var temp1 = JSON.parse(JSON.stringify(obj1));
console.log(obj1);
console.log(temp1);
obj1.arr[0] = "obj修改了";
obj1.arrayOfObjs[0] = "111";
console.log(obj1);
console.log(temp1);

 由此可分不同情况进行逻辑封装:

let obj1 = {
  // typeof 数组|对象 => 'object'
  // Array.isArray()
  arr: [1, 2, 3],
  arrayOfObjs: [{ c: 5 }, { d: 6 }],
  date: new Date(),
  object: { val: 4 },
  // 增加一个属性
  fn: function () {
    // typeof fn ===> 'function'
    return 5;
  },
  set: new Set([7, 8, 9, { e: 10 }]),
  map: new Map([
    [11, "f"],
    [12, "g"],
  ]),
  reg: /[h-z]/,
};

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  // 预防环形对象的处理
  if (!deepClone.cached) {
    deepClone.cached = new WeakMap(); // 虚引用map
  }
  // 如果obj已经保存过,无需执行后续
  if (deepClone.cached.has(obj)) {
    return deepClone.cached.get(obj);
  }
  // 几大类型
  if (obj instanceof Map) {
    // 新建一个map 替代老Map
    let tmp = new Map();
    // 保存
    deepClone.cached.set(obj, tmp);
    for (let [key, value] of obj) {
      // of 取值 in是取key
      tmp.set(key, deepClone(value)); // value可能是引用数据类型,需要处理!!!!!
    }
    return tmp;
  } else if (obj instanceof Set) {
    // 结构类似[]
    let tmp = new Set();
    deepClone.cached.set(obj, tmp);
    for (let val of obj) {
      tmp.add(deepClone(val)); // value可能是引用数据类型,需要处理!!!!!
    }
    return tmp;
  } else if (obj instanceof RegExp) {
    let tmp = new RegExp(obj);
    deepClone.cached.set(obj, tmp);
    return tmp;
  } else {
    // 数组 + 对象
    // obj // 数组 || 对象
    // 1: 创建一个新的对象 或者 数组 new [???]
    let tmp = new obj.constructor(); // Array Object Date
    deepClone.cached.set(obj, tmp);
    for (let key in obj) {
      tmp[key] = deepClone(obj[key]); // value可能是引用数据类型,需要处理!!!!!
    }
    return tmp;
  }
}
let obj2 = {
  toObj: obj1,
};
obj1.toObj = obj2;
// obj1 => obj2 => obj1 => obj2 => obj1 => obj2 => obj1 环形对象
// JSON.parse(JSON.stringify(obj1)) 报错
let cloned = deepClone(obj1);
console.log(obj1)
console.log(obj2)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值