JS 浅拷贝 深拷贝

JS 浅拷贝 深拷贝

js关于对象拷贝机制有两种,一种是浅拷贝,一种是深拷贝, 两者都是针对复杂数据类型

概念

浅拷贝的理解 系统在在堆中重新开辟一块空间,把拷贝的值或地址全部存放在里面。如果拷 贝的对象第一层中有简单数据类型,那我们就直接拷贝它的值,修改新旧对象里其中之 一里的简单数据类型的值,另一个对象不受影响。如果是复杂数据类型,例如Object中 的类( {} ),Array数组,正则表达式,函数等,那我们只能拷贝原对象存放在栈中的地 址,修改新旧对象里复杂数据类型的任何一个值,另一个也会受影响,因为新旧对象里 引用数据类型指向的堆中同一块地址。

深拷贝的理解 系统同样在在堆中开辟一块新的空间,新对象完全拷贝原对象里的值,不管原对象中是否存在复杂类型,此时拷贝的不是其地址,而是值!修改两者其中一个的任何数据,另一个不会受影响。

浅拷贝逻辑代码的实现

如图所示,我们创建一个最简单的类

<什么是类?类是将同类对象的共同属性和行为抽象出来形成的一个相对复杂的数据类型, 这与结构体一样,都是为了描述一个相对复杂的对象。>

JS 浅拷贝 深拷贝 在这个obj类中,既有简单数据类型(值类型) 如name,age, 也有引用数据类型(复杂数据类型) here,其本质是个对象,其里面又是一个简单数据类型name,值为Monday。如果我想再创建一个变量例如obj2, 要把obj的值全部全部拷贝过来,该怎么做呢?非常简单,那首先我们先创建一个变量obj2,如图

第一种:Object.assign({},原对象名)

JS 浅拷贝 深拷贝 先不着急,可给obj2变量赋值为null,此时我们马上进行对象的浅拷贝操作,这里讲述的浅拷贝有四种方法,前两种是针对于类而言,后两种是针对数组而言。第一种是Object.assign({},obj),如图 JS 浅拷贝 深拷贝 注意Object.assign()括号里的先是一对{},再是原对象,也就是你要拷贝的对象,再将这个整体赋值给一个新变量obj2,我们再来打印一下这个obj2,看看是否完成了浅拷贝,如图JS 浅拷贝 深拷贝 此时我们完成了浅拷贝,大家可以尝试一下,obj和obj2的打印结果是完全相同的。那如果此时我改变新对象中的name的值,那原对象中的name的值是否会呢?我们来试试,如图

JS 浅拷贝 深拷贝

可以发现,虽然我们修改了新对象里的数据,但原对象里的数据并未受到影响,此时我们就符合了上面的定义,拷贝简单数据类型拷贝其值,修改后另一方不受影响。但如果此时我修改的是新对象里的类呢?原数据会受到影响吗?我们再来试试

JS 浅拷贝 深拷贝 我们发现,只是修改了新对象里的复杂数据类型里的数据,原对象里居然一起改动了,很魔幻,这就符合了定义,浅拷贝复杂数据类型时,我们只能拷贝其地址,修改其中任何一方的复杂数据类型,另一个都会受到影响。那我们如何做到一模一样的拷贝而且修改数据时另一方数据不受影响呢?这就是深浅拷贝的本质区别,我们稍后进行实现

第二种:展开运算符

浅拷贝的第二种方法是展开运算符,也称扩展运算符{…原数据名},具体使用如图所示

JS 浅拷贝 深拷贝 可以发现,{…原数据名}的方法也可以完成对原数据的拷贝,其也是浅拷贝,大家可以修改数据后控制台打印查看,实现结果和上述Object.assign()的结果一样。


上面两种都是针对等于类而言,下面我们学习一下针对数组而言的浅拷贝方式。 第一种是Array.prototype.concat(),第二种是Array.prototype.slice()

第三种: Array.prototype.concat()

JS 浅拷贝 深拷贝

第四种: Array.prototype.slice()

可以发现,Array.prototype.concat()的方法也可以完成拷贝,是浅拷贝,符合浅拷贝的概念,同理Array.prototype.slice()。

JS 浅拷贝 深拷贝 除此之外,还有一种for in 循环遍历实现浅拷贝的方法,如图

JS 浅拷贝 深拷贝 以上是几个实现浅拷贝的方法,注意理解浅拷贝的定义和几个固定语法格式。除此之外还有一些方法例如下包或者引js文件,大家可以下去研究,这里不需要详细讲。

深拷贝逻辑代码的实现

深拷贝的概念与理解在文章开头已经提到,这里不多说,直接上方法

第一种:手写递归函数

JS 浅拷贝 深拷贝

第二种:Json.parse(Json.stringfy())

JS 浅拷贝 深拷贝 可以看到Json.parse(Json.stringfy())方法同样完成了拷贝,那怎么判断是不是深拷贝呢?很简单,我们来修改一下原对象里的复杂数据类型的值,看看新对象会不会受影响就行了 如图 JS 浅拷贝 深拷贝 我们发现,修改了原对象obj里的here类里的值,新对象里面不受影响,说明此时我们已经完成了深拷贝。但是Json.parse(Json.stringfy())方法其实也有一些局限性,如图

JS 浅拷贝 深拷贝 打印结果如下

JS 浅拷贝 深拷贝 总结Json.parse(Json.stringfy())的局限性:

1.原对象里的symbol类型的值,undefined,function函数在JSON.parse(JSON.stringify())后会丢失键值对,控制台不打印

2.原对象里的正则表达式在JSON.parse(JSON.stringify())后会变成一个空对象

3.原对象里的NaN和Infinity在JSON.parse(JSON.stringify())后会变成null

4.原对象里的Date在拷贝之后,新对象里显示字符串

第三种:引包实现深拷贝

JS 浅拷贝 深拷贝

第四种:引入jQuery文件来进行深拷贝

JS 浅拷贝 深拷贝

JS 浅拷贝 深拷贝深浅拷贝主要考点就是对于数据类型的基本掌握,以及对两种概念的理解程度,在此基础上利用一些方法实现深浅拷贝的基本实现,这次关于深浅拷贝的文章就分享到这里。