You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript如何动态访问并更新任意深度嵌套对象的属性

问题背景

已经掌握通过变量配合方括号表示法访问平面对象属性的方法,但该方案仅支持无嵌套的单层对象,无法适配多层嵌套结构。当前需要处理包含不同深度层级属性的对象,实现通过变量动态访问、修改对应属性值的能力。

示例目标对象结构如下:

{
  settings: {
    datasets: [
      {
        label: "Suivi",
        type: "line",
        backgroundColor: "#2bb0e9",
        borderColor: "#2bb0e9",
        pointBackgroundColor: "#2bb0fc",
        pointBorderColor: "#2bb0fc",
        pointRadius: 0,
        data: [],
        cubicInterpolationMode: "monotone",
        tension: 0.4,
      },
    ],
  },
  config: {
    maintainAspectRatio: false,
    plugins: {
      legend: {
        display: false,
      },
      tooltip: {
        callbacks: {
          label: function (context) {
            let label = "";
            if (
              context.dataset.backgroundColor[context.dataIndex] !== "#f4f4f4"
            ) {
              label = context.formattedValue;
            } else {
              label = "No information";
            }
            return label;
          },
        },
      },
    },
  },
}

实际使用场景下,需要支持访问不同深度的属性,例如3层深度的object.config.maintainAspectRatio、5层深度的object.settings.datasets[0].backgroundColor等,要求实现一个动态更新对象的函数,入参为属性路径path和新值newValue。

此前已尝试两种实现思路,均存在明显缺陷:

  • 思路1:将完整属性路径存为单个字符串(例如"settings.datasets[0].label"),直接通过object[path]访问属性,方案完全无法生效
  • 思路2:将不同深度层级的路径拆分为字符串数组(例如["settings", "datasets", "0", "borderColor"]),通过多层if判断逐层级匹配路径长度完成赋值,代码冗余度极高,属于不良实践
优雅实现方案

不需要编写多层分支判断适配不同路径长度,核心逻辑仅需两步,可兼容任意深度的对象、数组嵌套场景:

  1. 路径标准化:将传入的路径统一处理为按层级拆分的键名数组,既支持带.、[]的字符串路径格式,也支持提前拆分好的数组路径格式。例如字符串settings.datasets[0].backgroundColor,只需将方括号包裹的数字替换为.数字格式,再按.拆分即可得到标准键数组。
  2. 逐层遍历赋值:从根对象开始逐层向下遍历,始终持有当前遍历层级的引用,遍历到路径最后一个键时直接赋值即可。遍历过程中如果遇到中间层不存在的情况,可根据下一个键的类型自动初始化空对象或空数组,避免访问报错。

完整代码实现

/**
 * 动态设置嵌套对象指定路径的属性值
 * @param {Object|Array} target 目标对象/数组
 * @param {string|Array} path 属性路径,支持字符串格式(如"a.b[0].c")或数组格式
 * @param {*} newValue 要设置的新值
 * @returns  修改后的目标对象
 */
function setNestedValue(target, path, newValue) {
  // 统一解析路径为标准化键数组
  const pathKeys = Array.isArray(path)
    ? path
    : path.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean);

  let current = target;
  for (let i = 0; i < pathKeys.length; i++) {
    const key = pathKeys[i];
    // 遍历到最后一个键时直接赋值
    if (i === pathKeys.length - 1) {
      current[key] = newValue;
      break;
    }
    // 中间层不存在时自动初始化结构,下一个键为数字则初始化为数组,否则初始化为对象
    if (current[key] == null) {
      current[key] = /^\d+$/.test(pathKeys[i + 1]) ? [] : {};
    }
    // 移动引用到下一层
    current = current[key];
  }
  return target;
}

/**
 * 配套的嵌套属性读取方法
 * @param {Object|Array} target 目标对象/数组
 * @param {string|Array} path 属性路径
 * @param {*} defaultValue 路径不存在时返回的默认值
 * @returns 读取到的属性值
 */
function getNestedValue(target, path, defaultValue = undefined) {
  const pathKeys = Array.isArray(path)
    ? path
    : path.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean);

  let current = target;
  for (const key of pathKeys) {
    if (current == null) return defaultValue;
    current = current[key];
  }
  return current ?? defaultValue;
}

使用示例

const chartConfig = {/* 此处为前文给出的示例对象 */};

// 修改3层深度属性
setNestedValue(chartConfig, "config.maintainAspectRatio", true);
// 修改5层深度带数组下标的属性
setNestedValue(chartConfig, "settings.datasets[0].backgroundColor", "#ff0000");
// 支持数组格式路径传参
setNestedValue(chartConfig, ["config", "plugins", "legend", "display"], true);

// 读取属性验证结果
console.log(getNestedValue(chartConfig, "settings.datasets[0].backgroundColor")); // 输出 #ff0000
console.log(getNestedValue(chartConfig, "config.maintainAspectRatio")); // 输出 true

该方案代码量固定,和属性嵌套深度无关,同时兼容对象、数组混合嵌套场景,支持两种路径传参格式,遍历过程自动补全不存在的中间层结构,不会出现访问报错。


内容的提问来源于stack exchange,提问作者FlowRan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:36:17