
本文详解如何编写一个 deepFilter(obj, filter) 函数,递归遍历任意深度的嵌套对象,对每个叶子值应用过滤条件,并仅保留满足条件的键值对及其完整路径结构,避免扁平化错误。
本文详解如何编写一个 `deepfilter(obj, filter)` 函数,递归遍历任意深度的嵌套对象,对每个**叶子值**应用过滤条件,并仅保留满足条件的键值对及其完整路径结构,避免扁平化错误。
在处理嵌套对象时,常见的误区是复用同一结果对象(如传入 resultObj 参数),导致子对象属性被意外挂载到顶层,破坏原始层级结构——这正是原实现输出 { a: 1, c: 2, i: 5, j: 6 }(扁平、丢失 b 和 h 包裹)的根本原因。
正确的思路是:为每一层递归创建独立的结果对象,并仅在子对象非空(即至少有一个通过过滤的属性)时,才将其作为值赋给当前层级的对应键。
以下是推荐实现:
function deepFilter(obj, filter) {
// 基础类型或 null 直接返回(不进入递归)
if (obj === null || typeof obj !== 'object') {
return obj;
}
const result = {};
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
const value = obj[key];
if (typeof value === 'object' && value !== null) {
// 递归处理嵌套对象
const subResult = deepFilter(value, filter);
// 仅当子对象中存在至少一个有效属性时,才保留该键
if (Object.keys(subResult).length > 0) {
result[key] = subResult;
}
} else {
// 叶子值:直接应用过滤函数
if (filter(value)) {
result[key] = value;
}
}
}
return result;
}
使用示例:
const obj = {
a: 1,
b: {
c: 2,
d: -3,
e: { f: { g: -4 } },
h: { i: 5, j: 6 }
}
};
const filter = (n) => n >= 0;
console.log(deepFilter(obj, filter));
// 输出:{ a: 1, b: { c: 2, h: { i: 5, j: 6 } } }
✅ 关键要点总结:
- ✦ 每次递归都新建
result = {},杜绝跨层级污染; - ✦ 使用
Object.prototype.hasOwnProperty.call(obj, key)更安全地检测自有属性(兼容Object.create(null)等边界情况); - ✦ 对子对象递归后,必须检查
Object.keys(subResult).length > 0,否则空对象会被错误保留(如e: {}或f: {}); - ✦ 显式处理
null(typeof null === 'object'是 JS 历史遗留陷阱); - ✦ 过滤逻辑严格区分:对象 → 递归 + 条件挂载;非对象 → 直接判断 + 条件挂载。
该实现兼顾健壮性、可读性与语义清晰性,适用于真实项目中的配置精简、数据脱敏、权限字段裁剪等场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











