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

如何实现子选择器值向上汇总至父选择器且不受顺序影响?

修复子选择器向父选择器汇总数据的顺序依赖问题

我需要将子选择器的revenue和sessions值汇总到对应的父选择器中,当前仅用两个选择器做测试,实际场景中选择器数量更多、类型也可能不同。现有JavaScript代码在父选择器位于对象前、子选择器在后时能正常工作,但交换两者在对象中的顺序后,汇总算法失效,请问有什么修复方法?

正常运行的代码示例

const ecommerceObj = {
    'header#section-header > div > div.Header__FlexItem.Header__FlexItem--fill.hidden-phone > nav > ul > li:nth-child(6) > a':
        {
            revenue: 4,
            sessions: 3,
        },
    'header#section-header > div > div.Header__FlexItem.Header__FlexItem--fill.hidden-phone > nav > ul > li:nth-child(6) > a > span':
        {
            revenue: 6,
            sessions: 8,
        },
};

function generateRollUpValues(ecommerceObj) {
    const getParent = (str) => {
        const idx = String(str).lastIndexOf(' > ');
        if (idx > 0) {
            return str.substr(0, idx);
        }
        return false;
    };
    const rollup = {};
    const rev = [];
    const keys = Object.keys(ecommerceObj);
    // eslint-disable-next-line no-plusplus
    for (let i = 0; i < keys.length; i++) {
        rev.push(keys[i]);
    }
    for (let t = rev.length - 1; t >= 0; t -= 1) {
        const key = rev[t];
        const current = ecommerceObj[key];
        const p = getParent(key);
        // console.log(key + ' -> ' + p);
        if (p && rollup[p] === undefined) {
            rollup[p] = {
                revenue: 0,
                sessions: 0,
            };
        }
        if (rollup[key] != undefined) {
            ecommerceObj[key].revenue += rollup[key].revenue;
            ecommerceObj[key].sessions += rollup[key].sessions;
        }
        if (p) {
            rollup[p].revenue += ecommerceObj[key].revenue;
            rollup[p].sessions += ecommerceObj[key].sessions;
        }
    }

    return ecommerceObj;
}
console.log(generateRollUpValues(ecommerceObj));

失效的代码示例(仅交换选择器顺序)

const ecommerceObj = {
    'header#section-header > div > div.Header__FlexItem.Header__FlexItem--fill.hidden-phone > nav > ul > li:nth-child(6) > a > span':
        {
            revenue: 6,
            sessions: 8,
        },
    'header#section-header > div > div.Header__FlexItem.Header__FlexItem--fill.hidden-phone > nav > ul > li:nth-child(6) > a':
        {
            revenue: 4,
            sessions: 3,
        },
};

问题原因

原代码的遍历逻辑依赖选择器在对象中的顺序:通过反转keys数组从后往前处理,只有当子选择器在对象中排在父选择器之后时,反转后子选择器才会先被处理,其数值才能被正确累加到父选择器的rollup缓存中。如果子选择器排在父选择器前面,反转后父选择器会先被处理,此时子选择器的汇总值还未计算,导致父选择器无法获取子选择器的数值。

修复方案

核心思路是按选择器的层级深度排序:层级越深(被>分割的片段数量越多)的选择器越先处理,确保子选择器始终在父选择器之前被处理,彻底摆脱对对象key顺序的依赖。

修改后的完整代码

function generateRollUpValues(ecommerceObj) {
    const getParent = (str) => {
        const idx = String(str).lastIndexOf(' > ');
        if (idx > 0) {
            return str.substr(0, idx);
        }
        return false;
    };
    const rollup = {};
    // 按选择器层级深度排序,层级深的先处理
    const sortedKeys = Object.keys(ecommerceObj).sort((a, b) => {
        const depthA = a.split(' > ').length;
        const depthB = b.split(' > ').length;
        return depthB - depthA;
    });

    for (const key of sortedKeys) {
        const current = ecommerceObj[key];
        const p = getParent(key);
        
        if (p && rollup[p] === undefined) {
            rollup[p] = {
                revenue: 0,
                sessions: 0,
            };
        }
        if (rollup[key] != undefined) {
            ecommerceObj[key].revenue += rollup[key].revenue;
            ecommerceObj[key].sessions += rollup[key].sessions;
        }
        if (p) {
            rollup[p].revenue += ecommerceObj[key].revenue;
            rollup[p].sessions += ecommerceObj[key].sessions;
        }
    }

    return ecommerceObj;
}

// 测试顺序颠倒的对象
const ecommerceObj = {
    'header#section-header > div > div.Header__FlexItem.Header__FlexItem--fill.hidden-phone > nav > ul > li:nth-child(6) > a > span':
        { revenue: 6, sessions: 8 },
    'header#section-header > div > div.Header__FlexItem.Header__FlexItem--fill.hidden-phone > nav > ul > li:nth-child(6) > a':
        { revenue: 4, sessions: 3 },
};

console.log(generateRollUpValues(ecommerceObj));
// 输出结果中父选择器的revenue应为10,sessions应为11

关键修改点

  1. 新增排序逻辑:通过split(' > ')计算选择器的层级深度,排序后确保子选择器(层级更深)优先处理
  2. 简化遍历逻辑:直接遍历排序后的keys数组,去掉原有的反转数组操作
  3. 保持核心汇总逻辑:原有的rollup缓存累加逻辑不变,确保子选择器的数值能正确传递给父选择器

内容的提问来源于stack exchange,提问作者Moro Owusu Afriyie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 08:25:56