06月13, 2019

js的深拷贝和浅拷贝

1.理解这些之前先理解一些概念:

js的数据类型

js有五种基本数据类型(简单数据类型) undefined,null,boolean,number,string,还有一种复杂的时数据类型(引用类型), 对象

undefined 是已声明未赋值的变量输出的 null就是不存在
<script>
  //基本数据类型 
  //他们的值在内存中占据着固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的副本,并且我们不能给基本数据类型的值添加属性
  var a = 1;
  var b = a;
  a = 222
  console.log(a, b) //222,1

  //引用数据类型
  //复杂的数据类型即是引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象
  var c = {
    name: 'zhang'
  }
  var d = c;
  c.title = 'san';
  d.age = 13;
  console.log(c, d) //{name: "zhang", title: "san"} {name: "zhang", title: "san"} 
</script>

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

2.浅拷贝

上面例子就是浅拷贝,有时候我们只是想备份数组,但是只是简单让它赋给一个变量,改变其中一个,另外一个就紧跟着改变,但很多时候这不是我们想要的

3.深拷贝

1.数组 可以用slice或者concat解决

<script>
  var a = [1, 2, 3, 4];
  var b = a.slice(0);
  var c = a.concat();
  a[0] = 5;
  console.log(a, b, c)
</script>

2.对象

  //对象的深拷贝实现原理: 定义一个新的对象,遍历源对象的属性 并 赋给新对象的属性
  var a={name:'zhangsan',age:12};
  var b=new Object()
  b.name=a.nme;
  b.age=a.age;
  b.age=67;
  console.log(a,b)

最简单的深拷贝(JSON.stringify() 和JSON.parse()) 先把对象使用JSON.stringify()转为字符串,再赋值给另外一个变量,然后使用JSON.parse()转回来即可。

  var a = {
    name: {
      id: '11'
    }
  };
  var b = JSON.parse(JSON.stringify(a));
  b.name.id = 5555
  console.log(b, a)   //   5555 '11'

利用es6扩展运算符进行深拷贝 其实应该也算是浅拷贝 有坑 只对顶层属性做了赋值,完全没有继续做递归之类的把所有下一层的属性做深拷贝。

当原本的对象的键值是普通的值时候正确

 //对象的深拷贝实现原理: 定义一个新的对象,遍历源对象的属性 并 赋给新对象的属性
  var a = {
    name: 'zhangsan',
    age: 12
  };
  var b = {
    ...a
  }
  b.age = 66;
  console.log(a, b)  //{name: "zhangsan", age: 12} {name: "zhangsan", age: 66}

当值是对象的时候

  //对象的深拷贝实现原理: 定义一个新的对象,遍历源对象的属性 并 赋给新对象的属性
  var a = {
    name: {
      id: '11'
    }
  };
  var b = {
    ...a
  }
  // b.name = {
  //   id: '22'
  // };
  // console.log(a, b)  //{name:name: {id: "11"}}   {name:name: {id: "22"}}  

  b.name.id = '33'
  console.log(a, b)  //{name:name: {id: "33"}}   {name:name: {id: "3"}}  

Object.assign bug同上面一样 只赋值了第一层

 let obj1 = { a: 0 , b: { c: 0}};
  let obj2 = Object.assign({}, obj1);
  console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}

  obj1.a = 1;
  console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
  console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}

  obj2.b.c = 3;
  console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}//注意这里对象1里的c属性也发生了改变
  console.log(JSON.stringify(obj2)); // { a: 1, b: { c: 3}}

本文链接:http://zzl.bzpwhite.cn/post/js拷贝.html

-- EOF --

Comments