为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript 浅拷贝与深拷贝:实例和最佳实践

在处理 JavaScript 中的对象和数组时,创建数据结构的副本是一个常见的任务。然而,开发人员在选择是创建 浅复制 还是 深复制 时经常会遇到挑战。误解这两种复制的区别可能会导致代码意外产生副作用。让我们来了解一下这些概念、它们的区别以及何时该使用哪种复制。

(此处省略内容)

👉 下载电子书 (eBook) - JavaScript:从ES6到ES2023 (https://qirolab.gumroad.com/l/javascript-from-es2015-to-es2023)

《从ES2015到ES2023的JavaScript》的图片 "JavaScript从ES2015到ES2023"

此处省略内容

什么是浅复制?

浅拷贝会创建一个新的对象,其中复制了原始对象的顶层属性(如数字、字符串、布尔类型等)。对于对象属性(如数组或嵌套对象),则只复制了引用,而不是实际的数据。

这意味着新对象虽然有自己的顶级属性副本,但嵌套的对象和数组依然与原始对象共享着。

浅层复制的一个例子

    const original = {
      name: "Alice",
      details: {
        age: 25,
        city: "Wonderland"
      }
    };

    // 浅复制
    const shallowCopy = { ...original };

    // 修改浅复制中的嵌套的对象
    shallowCopy.details.city = "照镜城";

    // 原始对象也被修改了
    console.log(original.details.city); // 输出: "照镜城"

全屏进入 还原全屏

如何创建浅复制

  1. 使用扩展运算符 ...
       const 浅拷贝副本 = { ...原对象 };

进入全屏模式 切换到全屏模式

  1. 使用Object.assign()
       const 浅拷贝 = Object.assign({}, 原始对象);

点击全屏模式;点击退出全屏

虽然这些方法快速且简单,但它们不适用于高度嵌套的对象结构。

……此处省略……

什么是深度复制?

深拷贝会复制原始对象的所有属性及其子属性。这样可以确保副本与原始对象完全独立,修改副本不会影响到原始对象。

特别是当处理嵌套对象或数组等复杂数据结构时,特别是在数据完整性非常关键的情况下,深复制是必不可少的。

深拷贝示例(示例意为例子或范例)

(看看如何实现一个深拷贝)

    const original = {
      name: "Alice",
      details: {
        age: 25,
        city: "Wonderland"
      }
    };

    // 用JSON方式做了一个深拷贝
    const deepCopy = JSON.parse(JSON.stringify(original));

    // 修改了深拷贝里的嵌套对象
    deepCopy.details.city = "Looking Glass";

    // 原始对象没有改变
    console.log(original.details.city); // 结果是 "Wonderland"

全屏模式/退出全屏

如何创建一个深拷贝.

  1. 使用JSON.stringify()JSON.parse()
  • 首先将对象转换为JSON字符串,然后再将其解析回新的对象。

  • 限制包括:

  • 无法处理循环引用的情况。

  • 忽略掉函数、undefinedSymbol 等属性或值。
       const originalObject = 原始对象; // 深拷贝原始对象
       const deepCopy = JSON.parse(JSON.stringify(originalObject));

请进入全屏
请退出全屏

  1. 使用库(如)Lodash这样的库提供了强大的深层克隆功能。
       const _ = require('lodash');
       // 深拷贝原始对象
       const 深拷贝 = _.cloneDeep(原始对象);

全屏显示 退出全屏

  1. 自定义的递归函数
  • 为了实现完全控制,你可以编写一个递归函数来克隆嵌套的对象结构。

    • *

浅层拷贝和深层拷贝的对比

特性 浅拷贝 深拷贝
作用域 只复制顶级属性。 复制所有层级,包括嵌套数据。
引用 嵌套引用共享。 嵌套引用独立。
性能 更快且更轻量。 由于涉及递归操作,因此较慢。
使用场景 扁平的或嵌套较少的对象。 嵌套较深的对象或不可变的数据结构。

何时使用浅复制:

  • 扁平化对象:当处理没有嵌套属性的简单对象时。
  • 性能优化:当速度至关重要且不需要处理深层嵌套的数据时。
  • 临时修改:当你打算修改顶级属性但共享嵌套数据时。

示例使用方法

复制用户的设置,以便快速调整:

    const 用户设定 = { 主题: "深色", 布局: "网格布局" };
    const 更新后的设定 = { ...用户设定, 布局: "列表布局" };

全屏 退出全屏


什么时候需要用到深复制

  • 复杂结构:对于有多层嵌套结构的对象。
  • 避免副作用:当你需要确保副本的修改不会影响到原对象时。
  • 状态管理:在像 React 或 Redux 这样的框架中,保持不可变性至关重要。

示例用法

复制游戏或应用的状态:

    const gameState = {
      level: 5,
      inventory: {
        weapons: ["剑", "盾"],
        potions: 3
      }
    };

    // 这样做可以避免产生副作用
    const savedState = JSON.parse(JSON.stringify(gameState));

进入全屏 关闭全屏


常见的错误和坑

  1. 假设浅复制总是足够的话
  • 开发者常常错误地使用浅拷贝方法来处理嵌套对象时,导致原始数据意外被修改。

    1. 过度依赖 JSON 方法
  • 虽然 JSON.stringifyJSON.parse 很简单,但它们并不适用于所有对象(例如,包含方法或存在循环引用的对象)。

    1. 忽略性能,
  • 深拷贝可能更慢,特别是对于大对象,所以请酌情使用。

    • *

结论

理解浅拷贝和深拷贝之间的区别对于编写无bug的JavaScript代码来说至关重要。浅拷贝对于简单的结构很高效,而深拷贝对于复杂的、嵌套的对象则是必不可少的。根据你的需求选择合适的方法,并通过了解每种方法的限制来避免潜在的问题。


👉 电子书下载 - JavaScript:从ES2015版本到ES2023版本

javascript-from-es2015-to-es2023

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消