阅读 70

JavaScript 深拷贝浅拷贝

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

1. 数据类型

 数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和引用数据类型

  • 基本数据类型特点: 存储的是该对象的实际数据

  • 对象数据类型特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里

2. 复制数据

基本数据类型复制没问题:

     

但是当你复制对象/数组的时候就出现问题啦

为什么复制数组之后,修改了b的值,连a也一起修改了!!!?

在这里插入图片描述

为什么复制对象之后,修改了b的值,连a也一起修改了!!!?

在这里插入图片描述

先解释一下为什么会造成上图的结果

这些代码声明出来的变量在内存中是这样存储的。

在这里插入图片描述

在你用等号复制的时候,基本数据类型就会直接复制一个值,但是引用数据类型,只会新建一个指针,指向你原来的数据而已。

在这里插入图片描述

这就是浅拷贝

浅拷贝(shallowCopy):只是增加了一个指针指向被复制对象的内存地址,

 

那什么是深拷贝?

深拷贝(deepCopy):是增加了一个指针,并且申请了一个新的内存,使这个增加的指针指向这个新的内存。

 

当然了,补充一点: 不论你使用浅拷贝还是深拷贝,你删除一个变量的时候另一个不会被影响。

在这里插入图片描述

在这里插入图片描述

3. 常用的拷贝技术

3.1 concat()  数组浅拷贝

语法:array1.concat(array2,array3,...,arrayX)

参数:array2, array3, ..., arrayX,该参数可以是具体的值,也可以是数组对象。可以是任意多个。

返回值:Array 对象    返回一个新的数组。

在这里插入图片描述

3.2 slice() 数组浅拷贝

语法:array.slice(start, end)

参数:

  • start     可选。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推

  • end      可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

 

返回值:Array      返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

在这里插入图片描述

跟上边的情况一样,也是浅拷贝。

3.3 ...rest展开运算符 数组/对象浅拷贝

对数组进行浅拷贝

在这里插入图片描述

对象的浅拷贝

在这里插入图片描述

3.4 JSON.parse(JSON.stringify())  数组/对象深拷贝, 但不能处理函数数据

测试对象深拷贝成功了!

在这里插入图片描述

测试数组深拷贝也成功了!!

在这里插入图片描述

但是遇到函数就变成null了。因为json中只有对象和数组,没有函数。

在这里插入图片描述

 


4. 自定义深拷贝函数

所以怎么办?能不能自己写一个?:no_mouth:讲真只能自己写一个了。上代码:

代码

                     var a = [1, "22", [1, 1, 1], function() {}]

                     var b = copy(a)

                     // b[2] = 100000

                     console.log(a, b)

 

                     //获取数据类型,

                     function CheckType(variable) {

                            return Object.prototype.toString.call(variable).slice(8, -1)

                     }

                     //实现深拷贝

                     function copy(v) {

                            let result

                            let type = CheckType(v)

 

                            // 初始化result

                            if (type === "Object") {

                                   result = {}

                            } else if (type === "Array") {

                                   result = []

                            } else {

                                   result = v

                            }

 

                            //遍历目标数据

                            for (let i in v) {

                                   //获取目标数据的每一项

                                   let value = v[i]

                                   //判断每一项是否是数组或对象

                                   if (CheckType(value) === 'Object' || CheckType(value) === 'Array') {

                                          //递归处理嵌套的内容

                                          result[i] = copy(value)

                                   } else {

                                          result[i] = value

                                   }

                            }

                            return result

                     }

复制代码

 

解析

在这里插入图片描述

Object.prototype.toString.call(),调用该方法,默认返回当前对象的类型字符串,其格式为[object Xxx],其中Xxx就是对象的类型。然后使用字符串的slice()方法将类型分割出来。

在这里插入图片描述

扩展阅读:JavaScript 判断数据类型的6个方法

 

测试

下边测试一下,成功了嗷

在这里插入图片描述


晚安~

文章分类
前端
文章标签