如何通过含uid的路径数组过滤嵌套JavaScript对象?
基于UID路径过滤嵌套对象的正确实现
你的原代码核心问题是处理数组时,每次匹配到UID都会直接向过滤结果的数组中push新对象,导致同一条目重复添加。下面是修正后的实现方案,解决重复条目问题:
修正后的完整代码
const SEPARATOR = '.'; const filterDataByPath = (originalData, path, filteredData = {}) => { const pathChunks = path.split(SEPARATOR); const currentChunk = pathChunks[0]; const remainingPath = pathChunks.slice(1).join(SEPARATOR); // 处理普通属性键的情况 if (originalData.hasOwnProperty(currentChunk)) { const originalValue = originalData[currentChunk]; // 若为对象/数组且还有剩余路径,递归处理 if (typeof originalValue === 'object' && originalValue !== null && remainingPath) { filteredData[currentChunk] = filterDataByPath( originalValue, remainingPath, filteredData[currentChunk] || (Array.isArray(originalValue) ? [] : {}) ); } else { // 直接赋值属性值 filteredData[currentChunk] = originalValue; } } else { // 处理UID匹配数组元素的情况 const [arrayKey, targetItem] = Object.entries(originalData).reduce((result, [key, value]) => { if (Array.isArray(value)) { const found = value.find(item => item.uid === currentChunk); if (found) return [key, found]; } return result; }, []); if (!arrayKey || !targetItem) { throw new Error(`路径无效,未找到匹配的块:${currentChunk}`); } // 确保过滤结果中对应数组存在 if (!filteredData[arrayKey]) { filteredData[arrayKey] = []; } // 查找过滤结果数组中是否已存在该UID的对象,避免重复 let existingItem = filteredData[arrayKey].find(item => item.uid === currentChunk); if (!existingItem) { existingItem = { uid: currentChunk }; filteredData[arrayKey].push(existingItem); } // 递归处理剩余路径,复用已存在的对象 if (remainingPath) { filterDataByPath(targetItem, remainingPath, existingItem); } } return filteredData; }; // 使用示例 const obj = { topLevelProp1: 'some', topLevelProp2: 'data', topLevelPropArr: [{ uid: 'd7ed3623-e431-4bfa-85b3-8da14fa399c3', secLevelProp1: 123, secLevelPropArr: [{ uid: '15562309-22b7-4b11-a12e-b3374f0a7636', thirdLevelProp1: 'a plain value', thirdLevelProp2: { a: 'I am', b: 'a nested', c: 'object', }, }, { uid: '9394f313-b7bf-45fa-b8f3-683832ff7aa2', thirdLevelProp1: null, thirdLevelProp2: { a: 'I am also', b: 'another nested', c: 'object !!!', }, }], }, { uid: '04a487c6-9624-4b2e-8411-59a69c14f1e3', secLevelProp1: 456, secLevelPropArr: [{ uid: '58d4a3fd-734c-4c22-a0e3-f669e6ec7af3', thirdLevelProp1: 'another plain value', }], }], }; const paths = [ 'topLevelProp2', '04a487c6-9624-4b2e-8411-59a69c14f1e3.secLevelProp1', 'd7ed3623-e431-4bfa-85b3-8da14fa399c3.9394f313-b7bf-45fa-b8f3-683832ff7aa2.thirdLevelProp2.a', 'd7ed3623-e431-4bfa-85b3-8da14fa399c3.9394f313-b7bf-45fa-b8f3-683832ff7aa2.thirdLevelProp2.c', ]; let filteredData = {}; paths.forEach(path => { filteredData = filterDataByPath(obj, path, filteredData); }); console.log(JSON.stringify(filteredData, null, 2));
关键修改说明
- 避免数组重复条目:处理UID匹配的数组元素时,先在过滤结果的对应数组中查找是否已存在该UID的对象,存在则复用,不存在才创建新对象并入数组。
- 递归复用已有对象:递归处理剩余路径时,传入已存在的对象,确保同一路径的属性会合并到同一个对象中,不会生成新对象。
- 修复路径处理逻辑:用
slice(1)替代splice(1),避免修改原路径数组(splice会改变原数组,导致后续逻辑出错)。 - 完善空值判断:增加
originalValue !== null的判断,避免null被误判为对象处理。
内容的提问来源于stack exchange,提问作者karlitos
相关产品推荐
相关产品推荐

