JavaScript 深拷贝和浅拷贝

67 阅读3分钟

浅拷贝

浅拷贝: 只复制对象的顶层属性或元素,如果属性或元素是引用类型(如对象、数组等),则拷贝的是它们的引用地址,而不是实际的对象或数组本身的值

影响: 如果存在引用类型数据,那么进行浅拷贝后,两个对象中的引用类型数据会指向同一个地址,如果一个发生改变,则另一个也会发生同样的改变。

代码演示

// 原始数据
const bookType = {
    name: '童话',
    children: [
        {name: '格林童话'},
        {name: '一千零一夜'}
    ]
}

// 使用展开语法进行浅拷贝
const newBookType = {...bookType}
console.log("原始数据", bookType);
console.log("新对象" , newBookType);

其中children是引用类型数据,那么我们修改 bookTypenewBookType 其他一个 chilren,那么两个对象的children都会发生改变

newBookType.children[0].name = "like 童话"
console.log("==========修改children后的两个对象值");
console.log("原始数据", bookType);
console.log("新对象" , newBookType);

深拷贝

深拷贝:递归地复制对象的所有属性或数组的所有元素,包括引用类型数据,这就表示深拷贝得到的对象和原对象都是完全独立的,修改其中一个不会影响另一个

代码演示(如上例子)

深拷贝方式一:JSON.parse(JSON.stringify(拷贝对象)),但是这种深拷贝存在一个局限性和某些问题,比如

  1. 无法复制函数

  2. 无法处理循环引用

  3. 特殊对象类型丢失(Date、RegExp、Map、Set等)

  4. 性能问题(对于大型对象比较慢)

  5. 数据精度问题(对大数字或高精度数字会损失精度)

因为这里只是讲解两种拷贝,故不做深研究,针对深拷贝可以写个拷贝函数,处理拷贝中的各种数据类型

// 原始数据
const bookType = {
    name: '童话',
    children: [
        {name: '格林童话'},
        {name: '一千零一夜'}
    ]
}

// 深拷贝
const newBookType = JSON.parse(JSON.stringify(bookType))
console.log("原始数据", bookType);
console.log("新对象" , newBookType);

当修改其中一个,另一个不会受到影响

newBookType.children[0].name = "like 童话"
console.log("==========修改children后的两个对象值");
console.log("原始数据", bookType);
console.log("新对象" , newBookType);

业务场景

  1. 数据独立性: 当你需要两个完全独立的数据副本,保证其中的一个修改不会影响另一个

  2. 防止修改: 希望一个对象为只读,不希望直接修改它,可以深拷贝该对象,在需要时修改深拷贝的对象

  3. 避免副作用:在某些情况下,函数或方法可能会修改传入参数,但是你不希望输入参数发生改变,则可以深拷贝输入参数,对深拷贝得到的对象进行修改

  4. 持久化存储:深拷贝可以保证你拷贝对象中的所有属性或数组元素

影响

深拷贝比浅拷贝更消耗资源,因为它需要递归地复制对象的所有属性或数组中的所有元素,因此要注意系统性能