纯JS实现:按用户指定字段筛选未知对象属性(无第三方库)
实现支持嵌套字段(含数组)的对象属性筛选函数
需求:编写纯JavaScript函数,无需第三方库,支持指定嵌套字段路径(类似SQL SELECT语法),从任意结构的输入对象中提取对应属性,需处理嵌套数组场景。
示例数据
待筛选对象:
const responseObject = { name: 'John Doe', age: 25, cars: [ { name: "Test car", brand: "Test brand", accessories: [ { name: "Test accessory", description: "Test description", code: "1234" }, { name: "Test accessory", description: "Test description", code: "12345" } ] }, { name: "Test car 2", brand: "Test brand 2", accessories: [ { name: "Test accessory 2", description: "Test description 2", code: "1234" }, { name: "Test accessory 2", description: "Test description", code: "12345" } ] } ] };
指定保留字段:
const includedFields = { fields: [ "name", "cars.name", "cars.accessories.name" ] };
预期输出:
const changedResponse = { name: 'John Doe', cars: [ { name: "Test car", accessories: [ { name: "Test accessory", }, { name: "Test accessory", } ] }, { name: "Test car 2", accessories: [ { name: "Test accessory 2" }, { name: "Test accessory 2" } ] } ] };
原代码问题分析
你当前的代码存在几个关键问题:
- 变量名错误:
filter.split(".")中的filter未定义,应该是fieldPath - 循环逻辑错误:内层循环遍历的是
fieldsFilter.length,实际应该遍历fieldPathAttributes.length - 路径拼接逻辑错误:
currentAttributePath的赋值逻辑颠倒,导致路径拼接错误 - 缺失数组递归处理:遇到数组时,没有遍历数组元素并递归筛选属性
完整解决方案
以下是修复并完善后的函数,核心思路是递归遍历+路径逐步构建,统一处理对象和数组的嵌套场景:
function filterResponseFields(fieldsFilter, inputObject) { // 初始化结果对象 const result = {}; // 遍历每个需要保留的字段路径 fieldsFilter.forEach(fieldPath => { const pathSegments = fieldPath.split("."); let currentInput = inputObject; let currentResult = result; // 遍历路径的每一层 for (let i = 0; i < pathSegments.length; i++) { const segment = pathSegments[i]; const isLastSegment = i === pathSegments.length - 1; // 如果当前输入是数组,需要遍历每个元素递归处理 if (Array.isArray(currentInput)) { const arrayResult = []; // 遍历数组每个元素 currentInput.forEach(item => { // 递归处理单个元素,只保留当前剩余路径的字段 const filteredItem = filterResponseFields([pathSegments.slice(i).join(".")], item); if (Object.keys(filteredItem).length > 0) { arrayResult.push(filteredItem); } }); // 将处理后的数组挂载到结果对应位置 currentResult[segment] = arrayResult; break; } // 如果当前输入是对象 if (typeof currentInput === 'object' && currentInput !== null) { // 如果不是最后一段路径,确保结果中存在该层级的对象 if (!isLastSegment) { if (!currentResult[segment]) { currentResult[segment] = {}; } // 移动到下一层级的输入和结果 currentInput = currentInput[segment]; currentResult = currentResult[segment]; } else { // 最后一段路径,直接赋值对应属性 currentResult[segment] = currentInput[segment]; } } } }); return result; } // 测试调用 const filtered = filterResponseFields(includedFields.fields, responseObject); console.log(filtered);
关键逻辑说明
- 路径拆分:将每个字段路径按
.拆分成层级数组,方便逐层遍历 - 数组处理:遇到数组时,遍历每个元素并递归调用函数,只传递剩余的路径片段,确保数组内的对象也能正确筛选属性
- 结果构建:逐层创建结果对象的结构,确保嵌套层级与输入对象匹配,只保留指定字段
- 空值处理:递归处理后如果对象为空则不添加,避免生成无用的空结构
内容的提问来源于stack exchange,提问作者Marcelo Sant
相关产品推荐
相关产品推荐

