本文介绍如何对任意深度嵌套的对象数组递归计算每个节点在其同级兄弟节点中的 defaultWeight 占比,并将结果以 percent 字段写入原结构,支持深层嵌套、零值容错与非破坏性处理。
本文介绍如何对任意深度嵌套的对象数组递归计算每个节点在其同级兄弟节点中的 `defaultweight` 占比,并将结果以 `percent` 字段写入原结构,支持深层嵌套、零值容错与非破坏性处理。
在构建绩效评估、KPI 权重配置或树形指标体系时,常需将原始权重(如 defaultWeight)标准化为百分比形式,使其在每一层级内总和为 100%。由于数据结构呈树状嵌套(如 children 数组可无限递归),必须采用深度优先递归 + 同层归一化策略:先遍历当前层级,求出所有兄弟节点的 defaultWeight 总和;再逐个计算 defaultWeight / totalWeight * 100,并赋值给 percent;最后递归处理每个子节点的 children。
关键设计要点如下:
- ✅ 层级独立归一化:每个 children 数组单独计算其内部 defaultWeight 总和,互不影响;
- ✅ 空/零安全:当某层 totalWeight === 0 时跳过百分比计算,避免除零错误;
- ✅ 非破坏性处理:使用 structuredClone() 创建深拷贝,确保原始数据不被修改;
- ✅ 简洁可维护:单函数实现,无状态变量、无副作用(除目标对象自身赋值外)。
以下是完整、健壮的 TypeScript/JavaScript 实现:
/**
* 递归计算嵌套对象数组中各节点的 percent 字段(基于同级 defaultWeight 归一化)
* @param dataset - 待处理的节点数组(每个节点含 defaultWeight 和可选 children 数组)
* @returns void(直接修改传入数组的引用,建议传入克隆副本)
*/
function setPercent(dataset: { defaultWeight: number; percent?: number; children?: any[] }[]): void {
// 1. 计算当前层级所有节点的 defaultWeight 总和
const totalWeight = dataset.reduce((sum, node) => sum + (node.defaultWeight ?? 0), 0);
// 2. 遍历当前层级,设置 percent(仅当总和非零时,避免除零)
dataset.forEach(node => {
if (totalWeight !== 0) {
node.percent = Number(((node.defaultWeight ?? 0) / totalWeight * 100).toFixed(2));
}
// 3. 递归处理子节点(若存在且为数组)
if (Array.isArray(node.children)) {
setPercent(node.children);
}
});
}
// ✅ 使用示例:安全处理原始数据
const originalData = [/* ...你的嵌套数据 ... */];
const processedData = structuredClone(originalData); // 深拷贝,保护源数据
setPercent(processedData);
console.log(processedData);? 注意事项:
- structuredClone() 在较老环境(如 Node.js < 17.0 或部分旧版浏览器)中不可用,可替换为 JSON.parse(JSON.stringify(data))(要求数据为纯 JSON,不含函数、Date、undefined 等);
- 若需保留更多小数位,修改 .toFixed(2) 中的数字即可(如 toFixed(4));
- ?? 0 提供了对 null/undefined 的兜底,增强鲁棒性;
- 该函数原地修改传入数组,因此务必确保传入的是副本,而非原始引用。
此方案时间复杂度为 O(n)(每个节点访问一次),空间复杂度为 O(d)(递归调用栈深度 d,即最大嵌套层数),兼顾性能与可读性,适用于生产环境中的动态权重渲染、前端指标看板或后端数据预处理场景。










