js 浅拷贝和深拷贝的区别和应用

在 JavaScript 中,浅拷贝深拷贝都用于复制对象的内容,但它们在复制的方式和效果上有显著的区别。理解它们的差异对于避免常见的 bug 和正确使用数据结构非常重要。

1. 浅拷贝(Shallow Copy)

浅拷贝是指创建一个新的对象,但新的对象中仅复制原始对象的第一层属性(即原始对象的属性值)。如果属性值本身是一个对象或数组,那么它不会被复制,而是会保留对原始对象属性的引用。

特点:

  • 浅拷贝只复制对象的“第一层”属性,对于属性值是对象或数组的情况,它们仍然指向原始对象的引用。
  • 这样修改拷贝对象中的嵌套对象会影响到原始对象中的嵌套对象。

例子:

const obj = { a: 1, b: { c: 2 } };

const shallowCopy = { ...obj };  // 使用扩展运算符进行浅拷贝
shallowCopy.a = 10;             // 修改第一层的属性

shallowCopy.b.c = 20;          // 修改嵌套对象中的属性

console.log(obj);              // { a: 1, b: { c: 20 } }
console.log(shallowCopy);      // { a: 10, b: { c: 20 } }

解释:

  • shallowCopy.a = 10 只改变了第一层属性 a 的值,原始对象 obj 中的 a 仍然是 1
  • shallowCopy.b.c = 20 影响了 b 这个嵌套对象,因为它们仍然引用了同一个对象。

常见的浅拷贝方法:

  • 使用 Object.assign()
    const shallowCopy = Object.assign({}, obj);
    
  • 使用扩展运算符(...):
    const shallowCopy = { ...obj };
    

2. 深拷贝(Deep Copy)

深拷贝是指创建一个新的对象,并且递归地复制原始对象的所有属性,不管这些属性的值是原始类型(如字符串、数字、布尔值等),还是引用类型(如对象、数组等)。深拷贝会完全独立于原始对象,因此修改新对象中的属性不会影响原始对象。

特点:

  • 深拷贝会复制对象的所有层级,包括嵌套的对象或数组,确保没有任何引用关系。
  • 修改深拷贝后的对象,不会影响原始对象。

例子:

const obj = { a: 1, b: { c: 2 } };

const deepCopy = JSON.parse(JSON.stringify(obj));  // 使用 JSON 方法进行深拷贝
deepCopy.a = 10;
deepCopy.b.c = 20;

console.log(obj);          // { a: 1, b: { c: 2 } }
console.log(deepCopy);     // { a: 10, b: { c: 20 } }

解释:

  • deepCopy 是通过 JSON.parse(JSON.stringify()) 实现的深拷贝,这种方法可以确保 obj 中的每一层都被复制,并且是完全独立的。
  • 修改 deepCopy 中的属性 ab.c 不会影响 obj,因为它们不再共享引用。

常见的深拷贝方法:

  • 使用 JSON.parse(JSON.stringify(obj))(但有局限性,不能复制函数、undefinedSymbol 等,且无法处理循环引用)。
  • 使用递归方法手动实现深拷贝。
  • 使用第三方库(如 LodashcloneDeep 方法)。
// 使用 Lodash 的 deep clone 方法
const _ = require('lodash');
const deepCopy = _.cloneDeep(obj);

3. 浅拷贝与深拷贝的区别总结

特性 浅拷贝 深拷贝
复制深度 仅复制一层(第一层)属性 递归复制所有层级的属性
对引用类型的处理 仅复制引用类型的引用 复制引用类型的内容,完全独立
修改结果 修改嵌套对象会影响原始对象 修改拷贝对象不会影响原始对象
常见方法 Object.assign()、扩展运算符(... JSON.parse(JSON.stringify())、手动递归、Lodash.cloneDeep()

4. 浅拷贝和深拷贝的应用场景

  • 浅拷贝:

    • 用于复制对象的第一层属性,但不需要复制嵌套对象。适用于仅需要修改一层数据的场景。
    • 在组件状态管理中,如果对象的嵌套属性没有被修改,浅拷贝可以避免不必要的深度复制,提高性能。
  • 深拷贝:

    • 用于确保对象之间完全独立,特别是当对象中包含嵌套的引用类型(如数组或对象),且这些嵌套对象需要独立修改时。
    • 在需要避免对原始数据进行修改(如在状态管理中,或者操作不可变数据时)非常有用。

总结

  • 浅拷贝适用于只需要复制对象的第一层属性的场景,且不会影响引用类型的修改。
  • 深拷贝适用于需要确保完全独立的对象副本,尤其是在对象中包含嵌套引用类型时。

根据不同的应用场景选择适当的拷贝方式,能有效提高代码的效率和可靠性。

posted @   盘思动  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· Qt个人项目总结 —— MySQL数据库查询与断言
历史上的今天:
2022-11-08 /etc/profile、/etc/bashrc、~/.bash_profile、~/.bashrc 文件的作用
2022-11-08 linux java 安装
2022-11-08 tomcat 各个版本下载地址
2018-11-08 获取具体地址的经纬度
2017-11-08 array_unique后,数组本身的值并不会变
2017-11-08 rename table table1 to table2;
点击右上角即可分享
微信分享提示