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

js对象的深拷贝和浅拷贝(js中的深浅拷贝)



1. 浅拷贝的原理和实现

自己创建一个新的对象,来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象;但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响到另一个对象

方法一:object.assign

是 ES6 中  的一个方法,该方法可以用于 JS 对象的合并等多个用途,。该方法的第一个参数是拷贝的目标对象,后面的参数是拷贝的来源对象(也可以是多个来源)。

 
  

object.assign 的示例代码如下:

 
  

但是使用 object.assign 方法有几点需要注意

  • 它不会拷贝对象的继承属性;
  • 它不会拷贝对象的不可枚举的属性;
  • 可以拷贝  类型的属性。
 
  

从上面的样例代码中可以看到,利用  也可以拷贝  类型的对象,但是如果到了对象的第二层属性 obj1.a.b 这里的时候,前者值的改变也会影响后者的第二层属性的值,说明其中,也就是说

方法二:扩展运算符方式
  • 我们也可以利用 JS 的扩展运算符,在构造对象的同时完成浅拷贝的功能。
  • 扩展运算符的语法为:
 
  

扩展运算符 和  有同样的缺陷,也就是,但是如果属性都是

方法三:concat 拷贝数组

数组的  方法其实也是浅拷贝,所以连接一个含有引用类型的数组时,需要注意修改原数组中的元素的属性,因为它会影响拷贝之后连接的数组。不过  只能用于数组的浅拷贝,使用场景比较局限。代码如下所示。

 
  

方法四:slice 拷贝数组

 方法也比较有局限性,因为。,这一对象由该方法的前两个参数来决定原数组截取的开始和结束时间,是不会影响和改变原始数组的。

 
  

 
  

从上面的代码中可以看出,这就是。如果。因此深拷贝就是为了解决这个问题而生的,它能解决多层对象嵌套问题,彻底实现拷贝

手工实现一个浅拷贝

根据以上对浅拷贝的理解,如果让你自己实现一个浅拷贝,大致的思路分为两点:

  • 对基础类型做一个最基本的一个拷贝;
  • 对引用类型开辟一个新的存储,并且拷贝一层对象属性。
 
  

利用类型判断,针对引用类型的对象进行 for 循环遍历对象属性赋值给目标对象的属性,基本就可以手工实现一个浅拷贝的代码了

2. 深拷贝的原理和实现

。深拷贝则不同,对于复杂引用数据类型,其在堆内存中完全开辟了一块内存地址,并将原有的对象完全复制过来存放。

这两个对象是相互独立、不受影响的,彻底实现了内存上的分离。总的来说,:

将一个对象从内存中完整地拷贝出来一份给目标对象,并从堆内存中开辟一个全新的空间存放新对象,且新对象的修改并不会改变原对象,二者实现真正的分离。

方法一:JSON.stringify

 是目前开发过程中最简单的深拷贝方法,其实就是把一个对象序列化成为  的字符串,并将对象里面的内容转换成字符串,最后再用  的方法将  字符串生成一个新的对象

 
  

但是该方法也是有局限性的

  • 会忽略 
  • 会忽略 
  • 不能序列化函数
  • 无法拷贝不可枚举的属性
  • 无法拷贝对象的原型链
  • 拷贝  引用类型会变成空对象
  • 拷贝  引用类型会变成字符串
  • 对象中含有 、 以及 , 序列化的结果会变成 
  • 不能解决循环引用的对象,即对象成环 ()。
 
  

使用  方法实现深拷贝对象,虽然到目前为止还有很多无法实现的功能,但是这种方法足以满足日常的开发需求,并且是最简单和快捷的。而对于其他的也要实现深拷贝的,比较麻烦的属性对应的数据类型, 暂时还是无法满足的,那么就需要下面的几种方法了

方法二:基础版(手写递归实现)

下面是一个实现 deepClone 函数封装的例子,通过  遍历传入参数的属性值,如果值是引用类型则再次递归调用该函数,如果是基础数据类型就直接复制

 
  

虽然利用递归能实现一个深拷贝,但是同上面的  一样,还是有一些问题没有完全解决,例如:

  • 这个深拷贝函数并不能复制不可枚举的属性以及  类型;
  • 这种方法,而对于  这样的引用类型并不能正确地拷贝;
  • 对象的属性里面成环,即。

这种基础版本的写法也比较简单,可以应对大部分的应用情况。但是你在面试的过程中,如果只能写出这样的一个有缺陷的深拷贝方法,有可能不会通过。

所以为了“拯救”这些缺陷,下面我带你一起看看改进的版本,以便于你可以在面试种呈现出更好的深拷贝方法,赢得面试官的青睐。

方法三:改进版(改进后递归实现)

针对上面几个待解决问题,我先通过四点相关的理论告诉你分别应该怎么做。

  • 针对能够遍历对象的不可枚举属性以及  类型,我们可以使用  方法;
  • 当参数为  类型,则直接生成一个新的实例返回;
  • 利用  的  方法可以获得对象的所有属性,以及对应的特性,顺便结合  方法创建一个新对象,并继承传入原对象的原型链;
  • 利用  类型作为  表,因为  是弱引用类型,可以有效防止内存泄漏(你可以关注一下  和  的关键区别,这里要用 ),作为检测循环引用很有帮助,如果存在循环,则引用直接返回  存储的值

如果你在考虑到循环引用的问题之后,还能用  来很好地解决,并且向面试官解释这样做的目的,那么你所展示的代码,以及你对问题思考的全面性,在面试官眼中应该算是合格的了

实现深拷贝

 
  

 
  

我们看一下结果, 在  的基础上进行了一次深拷贝, 里的  数组进行了修改,并未影响到  的变化,如下图所示

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

版权声明


相关文章:

  • 上一章 目录 设置(上一章 目录 设置2063、金色月光 作者:魂如易 ...)2025-06-18 23:09:07
  • jsz是哪个明星的缩写(jz是哪位明星的缩写)2025-06-18 23:09:07
  • ubuntu16.04下载源(ubuntu software下载)2025-06-18 23:09:07
  • junit4下载教程(junit4.12下载)2025-06-18 23:09:07
  • vue3.0怎么安装(vuecli3安装)2025-06-18 23:09:07
  • 安装node环境 vue npm(node-v安装)2025-06-18 23:09:07
  • NT6打印机共享修复工具(nt6打印机共享修复工具v1.0.0.7免费版)2025-06-18 23:09:07
  • js数组方法filter(js数组方法splice)2025-06-18 23:09:07
  • Redhat9.0 root用户登录(redhat普通用户获取root权限)2025-06-18 23:09:07
  • js对象的深拷贝和浅拷贝(js对象的深拷贝和浅拷贝哪个好)2025-06-18 23:09:07
  • 全屏图片