深拷贝和浅拷贝是两种常见的数据复制方式,它们的主要区别在于复制后的数据类型是否与原数据类型一致,以及复制后的数据是否与原数据相互独立。
浅拷贝
浅拷贝指的是将一个对象或数组复制到一个新的对象或数组中,新的对象或数组中的元素是原对象或数组的引用 。也就是说,当修改新的对象或数组中的元素时,原对象或数组中对应的元素也会发生变化。
常见的浅拷贝方式有:
-
Object.assign()方法:该方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象。如果目标对象中已经存在相同的属性,则会覆盖该属性的值。
-
Array.prototype.concat()方法:该方法用于合并两个或多个数组,并返回一个新的数组。新数组中的元素是原数组中的元素的引用。
-
Array.prototype.slice()方法:该方法返回一个新的数组对象,包含原始数组的一部分。新数组中的元素是原数组中的元素的引用。
浅拷贝的优点:
速度快、占用内存少,适用于简单的数据结构
缺点:
无法复制嵌套的对象或数组,也无法实现真正的数据隔离
深拷贝
深拷贝指的是将一个对象或数组复制到一个新的对象或数组中,新的对象或数组中的元素与原对象或数组完全独立 。也就是说,当修改新的对象或数组中的元素时,不会影响原对象或数组中对应的元素。
常见的深拷贝方式有:
-
JSON.parse(JSON.stringify())方法:该方法先将数据转换为JSON字符串,再将JSON字符串转换为新的数据对象。这种方式可以复制任意层级的对象或数组,++但是无法复制函数、正则表达式等特殊类型的值。++
-
手动递归复制:该方式通过递归遍历原始对象或数组,将每个元素复制到新的对象或数组中。这种方式可以复制任意层级的对象或数组,也可以复制函数、正则表达式等特殊类型的值。
深拷贝的优点:
可以实现真正的数据隔离,适用于复杂的数据结构
缺点:
速度慢、占用内存多,需要注意避免循环引用的情况
注意细节
深拷贝和浅拷贝的区别在于复制后的数据是否与原数据完全独立,并且能否处理嵌套结构、特殊类型的值以及循环引用。
1. 数据类型
-
对于基本数据类型(如数字、字符串、布尔值等),无论是深拷贝还是浅拷贝,复制后的数据都是相互独立的,修改其中一个不会影响另一个。
-
对于引用数据类型(如对象、数组等),浅拷贝只是复制了引用,新对象或数组中的元素仍然指向原对象或数组中的相同元素。而深拷贝会递归地复制所有嵌套的对象或数组,新对象或数组中的元素与原对象或数组完全独立。
2. 嵌套结构
-
浅拷贝只能复制一层对象或数组的引用,如果原对象或数组中存在嵌套的对象或数组,复制后的对象或数组仍然会共享这些嵌套的引用。这意味着修改新对象或数组中的嵌套元素会影响到原对象或数组。
-
深拷贝可以复制任意层级的对象或数组,递归地复制每个嵌套的元素,确保新对象或数组与原对象或数组完全独立。
3. 特殊类型的值
-
使用JSON.parse(JSON.stringify())进行深拷贝时,会忽略函数、正则表达式、undefined等特殊类型的值。这是因为JSON.stringify()只能处理JSON安全的数据类型。
-
手动递归复制可以处理任意类型的值,包括函数、正则表达式等特殊类型。
4. 循环引用
-
循环引用指的是对象或数组中存在相互引用的情况。例如,对象A的某个属性引用了对象B,而对象B的某个属性又引用了对象A。在深拷贝时,需要注意避免出现循环引用,否则会导致无限递归。
-
一些深拷贝方法(如lodash.cloneDeep())会检测并处理循环引用的情况,确保复制过程不会陷入死循环。