当前位置:网站首页 > Vue.js开发 > 正文

js深拷贝和浅拷贝的方法(js深拷贝和浅拷贝的方法区别)



工作中经常会遇到需要复制 JavaScript 数据的时候,遇到 bug 时实在令人头疼;面试中也经常会被问到如何实现 一个数据的深浅拷贝,但是你对其中的原理清晰吗?一起来看一下吧!

想要更加透彻的理解为什么 JavaScript 会有深浅拷贝,需要先了解下 JavaScript 的数据类型有哪些,一般分为基本类型(Number、String、Null、Undefined、Boolean、Symbol )和引用类型(对象、数组、函数)。

基本类型是不可变的,任何方法都无法改变一个基本类型的值,也不可以给基本类型添加属性或者方法。但是可以为引用类型添加属性和方法,也可以删除其属性和方法。

基本类型引用类型在内存中的存储方式也大不相同,基本类型保存在栈内存中,而引用类型保存在堆内存中。为什么要分两种保存方式呢? 因为保存在栈内存的必须是大小固定的数据,引用类型的大小不固定,只能保存在堆内存中,但是我们可以把它的地址写在栈内存中以供我们访问。

说来这么多,我们来看个示例:

 
  

执行完这段代码,内存空间里是这样的:

clipboard.png

可以看到 obj1 和 obj2 都保存了一个指向该对象的指针,所有的操作都是对该引用的操作,所以对 obj2 的修改会影响 obj1。

小结:

之所以会出现深浅拷贝,是由于 JS 对 基本类型引用类型的处理不同。 基本类型指的是简单的数据段,而 引用类型指的是一个对象保存在堆内存中的地址,JS 不允许我们直接操作内存中的地址,也就是说不能操作对象的内存空间,所以,我们对对象的操作都只是在操作它的引用而已。

在复制时也是一样,如果我们复制一个基本类型的值时,会创建一个新值,并把它保存在新的变量的位置上。而如果我们复制一个引用类型时,同样会把变量中的值复制一份放到新的变量空间里,但此时复制的东西并不是对象本身,而是指向该对象的指针。所以我们复制引用类型后,两个变量其实指向同一个对象,所以改变其中的一个对象,会影响到另外一个。

浅拷贝只是复制基本类型的数据或者指向某个对象的指针,而不是复制对象本身,源对象和目标对象共享同一块内存;若对目标对象进行修改,存在源对象被篡改的可能。

我们来看下浅拷贝的实现:

 
  
 
  

深拷贝能够实现真正意义上的对象的拷贝,实现方法就是递归调用“浅拷贝”。深拷贝会创造一个一模一样的对象,其内容地址是自助分配的,拷贝结束之后,内存中的值是完全相同的,但是内存地址是不一样的,目标对象跟源对象不共享内存,修改任何一方的值,不会对另外一方造成影响。

 
  
 
  

两个方法可以合并在一起:

 
  

(1)若拷贝数组是纯数据(不含对象),可以通过concat() 和 slice() 来实现深拷贝;

 
  
 
  

(2)若拷贝数组中有对象,可以使用 concat() 和 slice() 方法来实现数组的浅拷贝。

 
   

无论 a[1].name 或者 b[1].name 改变,copy[1].name 的值都会改变。

 
   

改变了 a[1].name 后,copy[1].name 的值也改变了。


 
    
 
    

(2) 若拷贝对象有多级, Object.assign()、Object.create() 实现的是对象的浅拷贝。

 
     
 
     

修改了 targetObj.obj.str 的值之后,sourceObj.obj.str 的值也改变了。

对象的解构同 Object.assign() 和 Object.create(),都是一层(根级)深拷贝,之下的级别为浅拷贝。

(1)若拷贝对象只有一层,可以通过对象的解构来实现深拷贝;

 
     

(2)若拷贝对象有多层,通过对象的解构实现的是对象的浅拷贝。

 
      

用 JSON.stringify() 把对象转成字符串,再用 JSON.parse() 把字符串转成新的对象,可以实现对象的深复制。

 
      

可以看出,虽然改变了 copy[2].name 的值,但是 source[2].name 的值没有改变。

以下两种库都能实现深浅拷贝,有各自的使用方法。

jQuery

具体使用可以参考:官方文档

Lodash

具体使用可以参考:官方文档

到此这篇js深拷贝和浅拷贝的方法(js深拷贝和浅拷贝的方法区别)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • jsjsj是什么意思(js是啥意思是什么)2026-05-15 23:00:10
  • 前端跨域问题怎么解决(前端跨域怎么解决vue)2026-05-15 23:00:10
  • 打印机共享修复工具V2.1(打印机共享修复工具 知乎)2026-05-15 23:00:10
  • redhat enterprise 下载(redhat6.10下载)2026-05-15 23:00:10
  • ubuntu 源文件(ubuntu20.04 源)2026-05-15 23:00:10
  • vue中常用的生命周期钩子函数(vue生命周期函数详解)2026-05-15 23:00:10
  • vue2和vue3区别diff(vue2和vue3区别代码有什么区别)2026-05-15 23:00:10
  • vue安装router命令(vue中router的配置)2026-05-15 23:00:10
  • vue.js钩子函数(vue钩子函数作用)2026-05-15 23:00:10
  • ubuntu18.04源地址(ubuntu20.04 源)2026-05-15 23:00:10
  • 全屏图片