【JS基础】浅析深浅拷贝

435 阅读3分钟

前言

首先js有两种数据类型: 简单数据类型引用数据类型

对于简单数据类型的拷贝,并没有深浅拷贝的区别

我们讨论的深浅拷贝都只针对引用数据类型,拷贝时涉及到单个值和引用类型值的区别 (比如这个地方的obj1,已经是引用数据类型了,深浅拷贝后的obj2,obj3对象如果改变数据,是否给源数据obj1带来改变?这就是要研究的问题)

const obj1 = {
  //单个值
  name: "Tom", 
  age: 20,
  //引用类型值
  address: {
    province: "Guangdong",
    city: "Shenzhen",
  },
};
const shallow_copy_obj2 = {...obj1}; //浅拷贝对象shallow_copy_obj2

const deep_copy_obj3 = JSON.parse(JSON.stringify(obj1)); //深拷贝对象deep_copy_obj3

深拷贝和浅拷贝的关系:

在刚才的前言背景下,我们知道了

联系:深拷贝和浅拷贝是再复制一份数据的方法,也就是从源数据(origin)复制一份拷贝数据(origin_copy)出来

(这个地方origin就是obj1,origin_copy就是shallow_copy_obj2和deep_copy_obj3)

区别:它们最大的区别在于是否复制了数据中嵌套引用类型的数据(说人话,就是我这份拷贝数据的重新赋值操作是否会同时改变源数据) 我觉得可以总结为:深拷贝各立门户,浅拷贝藕断丝连

深拷贝:

深拷贝的数据(origin_deep_copy)是指拷贝数据(origin_copy)与源数据(origin)没有任何连带影响

原因就是在深拷贝的时候,是重新在堆区开辟一块内存空间(各立门户了),源对象与深拷贝对象共享引用,所以对深拷贝所做的任何更改都不会影响源对象。

const obj1 = {
  name: "Tom",
  age: 20,
  address: {
    province: "Guangdong",
    city: "Shenzhen",
  },
};
//还记得我们前言中深拷贝的deep_copy_obj3吗
const deep_copy_obj3 = JSON.parse(JSON.stringify(obj1));

deep_copy_obj3.age = 22;
deep_copy_obj3.address.city = "Guangzhou";

console.log(obj1);// {name: "Tom", age: 20, address: {province: "Guangdong", city: "Shenzhen"}}
console.log(deep_copy_obj3);// {name: "Tom", age: 22, address: {province: "Guangdong", city: "Guangzhou"}}

从控制台的输出结果可以看出,在对 obj1 进行深拷贝后,我们修改了 deep_copy_obj3 的年龄和地址信息,但原始对象 obj1 并没有受到影响。

如何实现深拷贝?

  • JSON.parse(JSON.stringify(obj))
  • Lodash 的 cloneDeep() 方法

浅拷贝:

浅拷贝的数据(origin_shallow_copy)是拷贝数据(origin_copy)与源数据(origin)可能有连带影响,为什么说可能呢?

因为浅拷贝仅拷贝了被复制对象的浅层内容(比如这个地方的a,没有嵌套更深的对象),因此新对象仍然是原来对象的引用

同样的例子

const obj1 = {
  //如果属性是基本类型,比如这个地方的name为string,age为number,拷贝的就是基本类型的值
  name: "Tom",
  age: 20,
  //如果属性是内存地址(引用类型),源拷贝给浅拷贝的就是obj1.address的内存地址
  address: {
    province: "Guangdong",
    city: "Shenzhen", //因此如果某一个浅拷贝对象改变了这个数据,就会影响到另一个对象
  },
};
//还记得我们前言中深拷贝的shallow_copy_obj2吗
const shallow_copy_obj2 = {...obj1}; //浅拷贝对象shallow_copy_obj2

shallow_copy_obj2.age = 30;
shallow_copy_obj2.address.city = "Guangzhou";

console.log(obj1);// {name: "Tom", age: 20, address: {province: "Guangdong", city: "Guangzhou"}}
console.log(deep_copy_obj3);// {name: "Tom", age: 30, address: {province: "Guangdong", city: "Guangzhou"}}

从控制台的输出结果可以看出,在对 obj1 进行浅拷贝后,我们修改了 shallow_copy_obj2 的年龄和地址信息,年龄属性是基本类型,对obj1没有改变,但obj1中的address.city发生了同样的改变

如何实现浅拷贝?

  • Object.assign() 方法
  • 扩展运算符 ...
  • Array.prototype.slice() 方法

注意要把赋值和浅拷贝区分开,赋值就是完全指向同一块内存了,连拷贝对象基本类型数据改变的同时也会影响到源数据

// 对象赋值 
const obj1 = {
  name: "Tom",
  age: 20,
  address: {
    province: "Guangdong",
    city: "Shenzhen",
  },
};
const obj4 = obj1; 
obj4.name = 'Andy'; 
obj4.address.province = "Guangzhou"; 
console.log('obj1===>', obj1); //obj1.name变为Andy,obj1.address.province也变为Guangzhou
console.log('obj4===>', obj4);