宝哥软件园

JS中的两种数据类型及实现引用类型深度复制的方法

编辑:宝哥软件园 来源:互联网 时间:2021-08-30

一.导言

我们知道,JS中的数据类型根据访问和存储方式的不同,可以分为基本类型和引用类型。

基本类型

基本类型有String、Boolean、Number、Undefined和Null,都是通过值传递的,也叫值类型。

参考类型

引用类型包括对象、数组和函数,都是通过引用来访问的。

二.存储方法的差异

因为基本类型和引用类型在内存中以不同的方式存储,所以访问它们的方式也不同。其中,基本类型存储在内存堆栈中,通过值访问;引用类型存储在内存堆中,通过引用进行访问。如下图所示:

当有

var n1=10var n2=10Vararr1=[1,2,3,4] Vararr2=[1,2,3,4]存储在内存中,如图所示:

值类型是直接存储在堆栈中的变量的实际值,而引用类型只存储堆栈中变量所指向的地址。从上图可以看出,值类型的变量n1和n2都是10,但是在栈中开辟了两个空间分别存储这两个变量,引用类型的变量arr1和arr2是一样的,但是在栈中只开辟了一个内存来存储,而这两个变量所指向的地址都存储在栈中。

三.复制差异

正是因为两者存储方式的不同,才造成了它们在复制上的不同。首先,看两段代码:

var n1=10//将n1复制到n2 var n2=n1n1=12console . log(n1);console . log(N2);首先定义变量n1=10,然后将n1复制到n2,然后将n1的值更改为12,并分别打印n1和n2的值。打印结果如下:

从结果中,我们可以看到n1变成12,但n2保持10。

看看另一段代码:

Var arr1=[1,2,3,4] //将arr1复制到arr2 var arr2=arr1//在arr1的尾部增加一个元素5 arr 1 . push(5);console . log(arr 1);console . log(arr 2);首先定义数组arr1,然后将arr1复制到arr2,然后在arr1的尾部添加一个元素,分别打印arr1和arr2的值。打印结果如下:

从结果中,我们可以看到,我们首先将arr1复制到arr2,但是当我们改变arr1时,arr2也随之改变。这证实arr1和arr2实际上指向内存中的同一地址。当arr1发生变化时,该存储器地址中的数据实际上会发生变化,arr2也指向该地址,因此arr2也会发生变化。

Arr2=arr1在上述代码中通常被称为浅拷贝。浅拷贝只拷贝变量名,在内存存储中不拷贝,指向同一个内存地址,导致一个变,另一个也变,这不是我们日常开发想要的。

那么如何实现真正的复制呢?

四.实现深度复制

真正的复制是复制后,arr1和arr2不再指向同一个内存地址,而是指向各自的地址,这样在发生变化时就不会同时发生变化,这就是所谓的深度复制。

接下来,我们封装一个深度复制函数来实现引用类型的深度复制:

//参数p是原始对象//参数c是原始对象的类型。如果原始对象是数组,传入的c是[]。如果原始对象是一个对象,传入的c是{},但默认值是{} function deepcopy (p,c) {var c=c | | {}。for(p中的var I){ if(p[I]的类型=='object'){ c[i]=(p[i]。构造函数===Array)?[]:{};deepCopy(p[i],c[i]) }else{ c[i]=p[i] } }返回c;五、测试

//参数p是原始对象//参数c是原始对象的类型。如果原始对象是数组,传入的c是[]。如果原始对象是一个对象,传入的c是{},但默认值是{} function deepcopy (p,c) {var c=c | | {}。for(p中的var I){ if(p[I]的类型=='object'){ c[i]=(p[i]。构造函数===Array)?[]:{};deepCopy(p[i],c[i]) }else{ c[i]=p[i] } }返回c;}//定义arr1 var arr1=[1,2,3,4] //将arr1复制到arr2 var arr2=deepCopy(arr1,[]);//在arr1的尾部增加一个元素5 arr 1 . push(5);console.log('arr1: ',arr 1);console.log('arr2: ',arr 2);测试结果:

从结果可以看出,arr1的变化不会引起arr2的变化,实现了真正的复制。

摘要

以上就是边肖介绍的JS中的两种数据类型以及实现引用类型深度复制的方法。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你的!

更多资讯
游戏推荐
更多+