JS--深拷贝和浅拷贝

344 阅读3分钟

参考文章:

  1. [JS]深拷贝与浅拷贝的区别,实现深拷贝的几种方法
  2. 你所不知道的JSON.stringify
  3. 彻底讲明白浅拷贝与深拷贝

数据结构和数据存储方式

在聊这个问题之前,我们得先捋一捋JavaScript的数据结构数据存储方式,JavaScript的数据结构主要分两种。

1.基本数据类型(六种):String、Number、Null、Underfined、Boolean、Symbol
2.引用数据类型(三种):Object、Array、Function

  • 基本数据类型的存储是key和value都存储在栈内存中。
    例如let a = 1;

  当你用b=a复制a时,会另外开辟了新内存空间存储b。

  你此时修改a和b的值,也互相不会影响。

  • 而引用类型的存储是key在栈内存中,但是value在堆内存中,栈内存仅仅是存储了堆内存的地址
    例如let aArr = [1,2,3,4,5];

  这个时候使用bArr=aArr复制aArr时,的确也是开辟了新内存空间存储bArr,但是问题在于,这个时候栈内存中的value值复制给bArr以后,这个只是一个地址罢了,并非具体的值,而这个地址同样的指向了同一个堆内存存储的值。好比一个房子在一街一号,然后另外一个房子也在一街一号,那这俩房子实际上就是同一个房子。


深拷贝和浅拷贝

  深拷贝和浅拷贝只是针对Array和Object这种复杂的数据结构来说,对基本数据类型是没有这种说法的。

常见的浅拷贝方法有:
1.Object.assign()
2.Array.prototype.concat()
3.Array.prototype.slice()

常见的深拷贝方法有:
1.JSON.parse(JSON.stringify())
2. 递归

浅拷贝

  看到下面这个例子,你是不是以为Object.assign()是深拷贝?你只看到了第一层,而它在大气层。(手动狗头)

  当object的属性只有一层的时候,Object.assign()是深拷贝,这是因为该对象中属性的值都是基本数据类型,也就是上面讲到的都存储在栈中,拷贝过去的时候就是直接复制了属性的值,但是一旦出现像是下面这种数据结构,属性的值是引用类型Array或者是Object的时候就暴露了自己是个浅拷贝的事实。其他两种浅拷贝方法也是同理。

深拷贝

  JSON.parse(JSON.stringify())转成JSON格式然后反转回来,这种方法固然简单方便,但是JSON是一个通用的文本格式,和语言无关。设想如果将函数定义也stringify的话,如何判断是哪种语言,并且通过合适的方式将其呈现出来将会变得特别复杂。特别是和语言相关的一些特性,比如JavaScript中的Symbol。诸如此类等等,所以坑非常多一不小心就会翻车,除非是数据结构特别简单一般不建议使用。更详细的说明可以参考 你所不知道的JSON.stringify

  递归的思路就是不断的往下查询,直到属性的值的类型是基础数据类型即可。