Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
递归更新嵌套对象中指定键及其祖先节点的数值_创想鸟

递归更新嵌套对象中指定键及其祖先节点的数值

递归更新嵌套对象中指定键及其祖先节点的数值

本教程详细讲解如何在一个多层嵌套的对象数组中,根据给定的唯一键值,递归地更新目标节点及其所有父节点的特定数值(curr),同时避免修改最顶层(根级别)的节点。文章将分析常见问题,并提供一个高效的JavaScript递归解决方案,确保更新的准确性和层级控制。

1. 问题定义与数据结构

在前端开发或数据处理中,我们经常会遇到树形或嵌套的数据结构。假设我们有一个表示分类或层级关系的对象数组,其结构如下:

const data = [  {    key: "id1",    name: "Category 1",    curr: 0,    total: 0,    nodes: [      {        key: "id2",        name: "Applications",        curr: 20,        total: 30,        nodes: [          {            key: "id3",            name: "Gaming",            curr: 5,            total: 10,            nodes: []          },          {            key: "id4",            name: "Operating System",            curr: 15,            total: 20,            nodes: []          }        ]      }    ]  },  {    key: "id5",    name: "Category 2",    curr: 0,    total: 0,    nodes: [      {        key: "id6",        name: "Sub Category",        curr: 12,        total: 48,        nodes: [          {            key: "id7",            name: "Inside Sub",            curr: 12,            total: 48,            nodes: []          }        ]      }    ]  },  {    key: "id8",    name: "Last One",    curr: 0,    total: 0,    nodes: []  }];

每个对象都包含一个唯一的 key、name、curr(当前值)、total(总值)以及一个 nodes 数组,用于表示其子节点。我们的目标是实现一个函数,当传入一个 key 时,能够找到对应的节点,将其 curr 值递增,并且将此递增操作向上回溯,使其所有祖先节点的 curr 值也相应递增。但需要特别注意的是,最顶层(根级别,即 data 数组中的直接元素,如 id1, id5, id8)的 curr 值不应被修改。

例如,如果调用 incrementRecursively(data, “id4”),预期输出应为:id4 的 curr 从 15 变为 16,其父节点 id2 的 curr 从 20 变为 21。而 id1(根节点)的 curr 保持不变。

2. 常见尝试及局限性

初次尝试解决此类问题时,开发者可能会倾向于使用简单的递归遍历,如下所示:

const incrementRecursively = (nodes, key) => {  const increment = (currentNodes, targetKey) => {    currentNodes.forEach((node) => {      if (node.key === targetKey) {        node.curr++; // 找到目标,递增      }      if (node.nodes && node.nodes.length) {        // 递归处理子节点        increment(node.nodes, targetKey);      }    });  };  increment(nodes, key);  return nodes;};

这种方法的问题在于,它只能找到并修改指定 key 的节点。当目标节点被修改后,它不会向其父节点传递任何信息,因此父节点的 curr 值不会被更新。此外,它也没有机制来区分根节点和其他层级的节点,从而无法实现“不修改根节点”的需求。

3. 递归解决方案:深度追踪与状态传递

为了解决上述问题,我们需要一种机制,让递归函数在子节点发生更新时,能够通知其父节点。同时,我们需要一个参数来追踪当前节点的深度,以便在更新时排除根节点。

3.1 核心思路

状态回传: 递归函数不再仅仅执行操作,而是返回一个布尔值,表示在其当前子树中是否发生了 curr 值的递增。深度追踪: 引入一个 depth 参数,在每次递归深入时递增。通过判断 depth 的值,我们可以区分根节点(depth = 0)和非根节点(depth > 0)。条件更新: 只有当 depth > 0 且当前节点或其子节点发生了 curr 值递增时,才递增当前节点的 curr 值。

3.2 示例代码与详细解析

function updateParentChildCurr(nodes, targetKey, depth = 0) {  // 遍历当前层级的节点  for (let node of nodes) {    // 检查当前节点是否是目标节点,或者其子节点中是否找到了目标节点并进行了更新    // `node.nodes ?? []` 确保即使 node.nodes 为 undefined 或 null 也能安全地进行递归调用    if (node.key === targetKey || updateParentChildCurr(node.nodes ?? [], targetKey, depth + 1)) {      // 如果满足上述条件(即当前节点或其子节点发生了更新)      // 并且当前节点不是根节点(depth > 0)      if (depth > 0) {        node.curr++; // 递增当前节点的 curr 值      }      // 返回 true,向上层级通知:该路径上发生了更新      return true;    }  }  // 如果遍历完当前层级的所有节点,都没有找到目标或子节点未更新,则返回 false  return false;}// 示例调用console.log("原始数据:", JSON.stringify(data, null, 2));// 调用函数,更新 key 为 "id4" 的节点及其父节点updateParentChildCurr(data, 'id4');console.log("n更新 'id4' 后的数据:", JSON.stringify(data, null, 2));// 再次调用,更新 key 为 "id7" 的节点及其父节点updateParentChildCurr(data, 'id7');console.log("n更新 'id7' 后的数据:", JSON.stringify(data, null, 2));

代码解析:

function updateParentChildCurr(nodes, targetKey, depth = 0):nodes: 当前函数调用处理的节点数组。targetKey: 我们要查找并更新的节点的 key。depth = 0: 默认参数,表示当前处理的节点数组的深度。顶层 data 数组的深度为 0。每当递归深入一层,depth 就会加 1。for (let node of nodes): 迭代当前 nodes 数组中的每一个节点。if (node.key === targetKey || updateParentChildCurr(node.nodes ?? [], targetKey, depth + 1)): 这是核心逻辑所在。node.key === targetKey: 检查当前节点是否就是我们要找的目标节点。如果是,说明我们已经找到了要递增的节点。updateParentChildCurr(node.nodes ?? [], targetKey, depth + 1): 如果当前节点不是目标,则递归调用自身,处理当前节点的子节点。node.nodes ?? []: 使用空值合并运算符 (??),确保如果 node.nodes 是 null 或 undefined,也能安全地传递一个空数组,避免运行时错误。depth + 1: 递增深度,表示我们进入了下一层。|| 运算符:这个逻辑非常关键。如果 node.key === targetKey 为 true(当前节点是目标),或者递归调用 updateParentChildCurr 返回 true(表示在当前节点的某个子孙节点中找到了目标并进行了更新),那么整个 if 条件就为 true。这意味着在当前 node 的路径上,要么是 node 本身,要么是其子孙节点发生了 curr 值递增。if (depth > 0): 如果 if 条件为 true,我们知道当前路径上发生了更新。此时,我们检查 depth。只有当 depth 大于 0 时(即当前节点不是根节点),才执行 node.curr++。这完美地满足了“不修改根节点”的要求。return true: 当 if 条件满足(即找到了目标并/或更新了父节点)时,函数立即返回 true。这个 true 值会向上层调用者传递,告知其父节点也需要考虑更新自己的 curr 值。return false: 如果 for 循环结束,没有找到 targetKey 对应的节点,也没有在其任何子孙节点中找到,那么函数返回 false,表示当前路径上没有发生更新。

4. 注意事项

原地修改 (In-place Modification): 上述解决方案直接修改了原始 data 数组。在许多应用场景中,这可能是可以接受的。但如果需要保持数据的不可变性(例如在 React/Redux 应用中),则需要在每次修改时创建新的对象和数组副本。这会使代码更复杂,但能避免副作用。depth 参数的重要性: depth 参数是实现层级控制的关键。通过它,我们可以精确地决定哪些层级的节点应该被修改,哪些不应该。key 的唯一性: 该解决方案假设 key 在整个树形结构中是唯一的。如果 key 不唯一,则可能会更新多个匹配的节点及其祖先。鲁棒性: node.nodes ?? [] 的用法增强了代码的鲁棒性,能够处理 nodes 属性可能缺失或为 null/undefined 的情况,避免了潜在的 TypeError。

5. 总结

通过结合递归遍历、深度追踪参数以及利用函数返回值作为状态传递机制,我们成功地实现了一个高效且准确的解决方案,用于在嵌套对象数组中根据指定键递归更新目标节点及其所有父节点的特定数值,同时遵守了不修改根节点的特定业务规则。这种模式在处理树形数据结构时非常有用,可以灵活应用于各种复杂的层级数据操作场景。

以上就是递归更新嵌套对象中指定键及其祖先节点的数值的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1520224.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Node.js中路径字符串显示双反斜杠的解析与处理
上一篇 2025年12月20日 13:08:17
使用JavaScript实现键盘事件控制的秒表教程
下一篇 2025年12月20日 13:08:27

相关推荐

  • WordPress插件定制:使用Filter Hook修改邮件通知接收者

    本教程将指导您如何在WordPress中利用Filter Hook定制插件行为,特别是修改第三方插件的邮件通知接收者。我们将详细讲解如何识别目标Filter、理解其参数,并正确编写回调函数来拦截或修改数据,以实现自定义的邮件发送逻辑,避免因参数不匹配导致的错误。 WordPress Hook机制概览…

    2026年9月21日
    100
  • 谷歌浏览器官方在线访问 最新版Chrome官网登录

    谷歌浏览器官方在线访问入口是https://www.google.cn/chrome/,提供简洁界面、跨设备同步、高效内核、安全防护和丰富扩展生态。 谷歌浏览器官方在线访问入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来最新版Chrome官网登录地址,想要获取纯净浏览体验的网友一起随小…

    2026年9月21日
    200
  • Java Collections.singletonList如何创建单元素集合

    Collections.singletonList(T item) 返回只含一个元素的不可变列表,传入指定对象后生成轻量级只读集合,适用于需高效传递单元素场景。该列表禁止修改操作,否则抛出异常,允许 null 元素,内部优化减少内存开销,常用于 API 参数传递或流处理中的临时数据构造。 Java …

    2026年9月21日
    100
  • JavaScript中的模块联邦如何实现微前端的代码共享?

    模块联邦通过运行时动态加载实现微前端代码共享,无需打包公共依赖。使用 ModuleFederationPlugin 配置 name、remotes、exposes 和 shared,使应用可暴露或引入远程模块,支持组件、工具函数及状态管理共享,提升复用性并减少冗余。 模块联邦通过在构建时让不同应用直…

    2026年9月21日
    200
  • 天眼查app怎么看一个公司的法院判决书_天眼查公司法院判决书查询

    通过天眼查App可查询公司法律纠纷详情。首先登录并搜索企业名称进入主页,再点击“法律诉讼”板块查看案件列表,最后筛选已结案案件并点击查看裁判文书获取判决书全文,部分敏感信息可能不予展示。 如果您想了解一家公司涉及的法律纠纷详情,查阅其法院判决书是重要的途径之一。天眼查App整合了公开的司法信息,可以…

    2026年9月21日
    000
  • 如何通过tracert命令追踪数据包从本地到目标服务器的完整路径?

    打开命令提示符,输入cmd并回车;2. 执行tracert 目标地址命令追踪路径;3. 查看每跳响应时间与IP,分析延迟变化定位网络瓶颈;4. 注意部分节点可能因防火墙不响应导致超时。 使用 tracert(Windows 系统)命令可以追踪数据包从你的计算机到目标服务器所经过的每一跳网络节点,帮助…

    2026年9月21日
    1000
  • windows怎么清除dns缓存_dns缓存刷新命令详解

    1、刷新DNS缓存可解决网页无法加载或域名解析错误问题。2、通过命令提示符执行ipconfig /flushdns清除系统DNS缓存。3、以管理员身份运行命令提示符并重启DNS Client服务(net stop dnscache和net start dnscache)恢复服务功能。4、在Chrom…

    2026年9月21日
    000
  • Linux interfaces 虚拟网络类型了解01

    Linux interfaces 虚拟网络类型了解01Linux interfaces 虚拟网络类型了解01Linux interfaces 虚拟网络类型了解01Linux interfaces 虚拟网络类型了解01

    在osi模型的定义中,数据链路层和物理层,以及传输层和网络层执行的任务在概念上相似:它们都提供了数据传输的方式,即沿着特定路径将数据从源点传输到目的地的方法。然而,数据链路层和物理层负责跨物理路径的通信服务,而传输层和网络层则提供由多个数据链路组成的逻辑路径或虚拟路径的通信服务。 Bridge操作指…

    2026年9月21日 • 用户投稿
    000
  • iPhone声音小如何解决

    确认音量是否被调低 第一步,检查iPhone的音量是否被误调至最低。可以通过按压手机左侧的音量加减键,观察屏幕上的音量条是否处于合理范围。同时留意是否启用了静音模式——手机左侧的静音开关若拨到静音位置(显示橙色),声音会明显变小甚至无声,将其拨回非静音状态即可恢复正常。 清洁扬声器孔 扬声器出声孔被…

    2026年9月21日
    000
  • PHP简易路由框架构建:从URL解析到动态控制器加载的实践指南

    本文旨在指导读者构建一个基础的PHP路由系统,实现URL路径到控制器方法的高效映射。内容涵盖URL解析、控制器动态加载、方法调用以及关键的错误处理机制,特别强调如何避免常见的“未定义变量”错误和文件包含路径问题,确保路由系统稳定且易于维护。 一、路由系统核心原理 构建一个简单的php路由系统,其核心…

    2026年9月21日
    200
  • 如何在Java中理解Java I/O与NIO机制

    传统I/O是阻塞式流模型,适用于低并发场景;NIO基于缓冲区与通道,支持非阻塞和多路复用,适合高并发网络应用,核心区别在于线程模型与资源利用率。 Java中的I/O(输入/输出)与NIO(New I/O)是处理数据读写的核心机制,理解它们的区别和使用场景对开发高性能应用至关重要。传统I/O基于流模型…

    2026年9月21日
    100
  • UC浏览器网页上的文字无法选中复制怎么办 UC浏览器解决网页文字禁止复制问题

    答案:可通过开发者工具、阅读模式、打印预览、OCR识别或自定义脚本解除UC浏览器网页复制限制。具体操作依次为:开启开发者工具并执行JavaScript代码解除限制;启用阅读模式净化页面内容;使用打印预览重新渲染页面以选中文字;对截图应用OCR技术提取文本;添加书签脚本自动移除禁用选择的代码,从而实现…

    2026年9月21日
    100
  • JavaScript中的尾调用优化(TCO)在ES6中如何工作?

    尾调用是指函数的最后一个动作调用另一个函数,ES6引入尾调用优化以重用栈帧、避免内存溢出,支持真正的尾递归,如阶乘函数通过累积参数实现。 尾调用优化(Tail Call Optimization, TCO)是ES6引入的一项语言特性,目的是在特定条件下重用函数调用栈帧,避免不必要的内存增长,从而支持…

    2026年9月21日
    200
  • 为什么iPhoneSE2022屏幕无响应如何强制重启?快速按音量键后长按电源键

    首先尝试强制重启,若无效则检查充电状态,最后可通过恢复模式重装系统。具体为:1. 按音量+、音量-后长按电源键10秒以上;2. 充电15分钟观察是否响应;3. 连电脑进入恢复模式恢复系统。 如果您尝试唤醒或操作您的iPhone SE(2022款),但屏幕无响应或显示黑屏,可能是系统临时卡死或软件冲突…

    2026年9月21日
    100
  • Java语法基础有哪些新手必学的核心知识

    掌握Java基本数据类型与变量声明,如int、double、char和boolean,并理解强类型语言特性;2. 熟悉运算符与表达式,包括算术、比较和逻辑运算符,奠定程序逻辑基础。 Java语法基础是每个初学者必须掌握的内容,只有打好根基,才能顺利进阶面向对象编程和实际项目开发。以下是新手必学的核心…

    2026年9月21日
    300
  • win10连接打印机错误0x00000709怎么办_win10打印机连接错误修复方法

    错误代码0x00000709通常因权限不足、系统更新冲突或服务异常导致共享打印机连接失败。可使用专业工具一键修复,或通过修改注册表权限、卸载KB5005569等特定更新、重启Print Spooler及相关服务,以及添加Windows凭据(如IP地址和guest账户)解决该问题。 当您在Window…

    2026年9月21日
    200
  • 升级X86架构性能大提升!极空间Z2 Ultra图赏

    升级X86架构性能大提升!极空间Z2 Ultra图赏升级X86架构性能大提升!极空间Z2 Ultra图赏升级X86架构性能大提升!极空间Z2 Ultra图赏升级X86架构性能大提升!极空间Z2 Ultra图赏

    10月23日,极空间正式推出全新双盘位nas产品——极空间z2 ultra,官方售价为1899元,参与国家补贴后仅需1457元,性价比进一步提升。 此次发布的Z2 Ultra最大的亮点在于采用X86架构处理器,相较以往使用的ARM平台,性能实现飞跃式提升,运行速度显著加快。更重要的是,新架构对Doc…

    2026年9月21日 • 用户投稿
    300
  • 数据库分库分表(Sharding)策略

    在现代应用程序中,随着数据量的增长,单一数据库的性能和容量往往难以满足需求。这时,数据库分库分表(Sharding)策略就成了一个关键的解决方案。那么,如何设计和实现一个有效的分库分表策略呢?让我们深入探讨一下。 在我的职业生涯中,我曾多次参与大型项目的数据库优化,其中分库分表是常见的挑战之一。我记…

    2026年9月21日
    000
  • 抖音电商与独立商城怎么结合?流量互通与转化全攻略

    许多自建电商平台的运营者正积极探索与抖音电商的合作路径,以期借助其庞大的用户基数实现流量增长和销售转化提升。虽然抖音能为独立商城导入可观的新用户,但要真正实现高效联动,必须依赖技术系统的深度对接与精准的内容运营策略。以下是抖音与独立商城融合的关键路径及实操建议。 如何实现抖音与独立商城的店铺互通? …

    2026年9月21日
    100
  • 如何在Java中实现个人财务管理工具

    首先设计Transaction、FinanceManager和Budget核心类,实现交易记录、统计分析与预算控制功能,通过ArrayList管理数据,使用LocalDate处理日期,结合ObjectOutputStream持久化存储,初期采用Scanner构建控制台菜单实现增删查改与报表展示,后期…

    2026年9月21日
    100

发表回复

登录后才能评论
关注微信