
本文介绍一种递归式对象深度过滤方法,通过 deepFilter(obj, filter) 函数对任意嵌套对象执行值级条件筛选,仅保留满足回调函数条件的键值对,并严格维持原始嵌套层级结构。
本文介绍一种递归式对象深度过滤方法,通过 `deepfilter(obj, filter)` 函数对任意嵌套对象执行值级条件筛选,仅保留满足回调函数条件的键值对,并严格维持原始嵌套层级结构。
在处理嵌套对象时,常见的错误是将深层属性“扁平化”提取(如把 b.h.i 直接挂到顶层),导致结构丢失。核心问题在于:过滤必须按层级递归进行,且每个子对象的筛选结果需独立构造、独立判断是否保留,而非共享同一结果对象或跳过空子树检查。
正确的实现应遵循以下逻辑:
- 对每个键值对,先判断值是否为对象;
- 若是对象,则递归调用
deepFilter处理该子对象,得到其过滤后的子结果; - 仅当该子结果非空对象(即
Object.keys(subObj).length > 0)时,才将其以原键名挂载到当前结果中; - 若值为原始类型(如数字、字符串),则直接用
filter(value)判断是否保留; - 始终为每一层递归创建全新的空对象
{}作为result,避免引用污染与结构塌陷。
以下是经过验证的专业实现:
function deepFilter(obj, filter) {
// 边界处理:非对象直接返回(如 null、undefined、原始值)
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;
}✅ 关键改进点说明:
- 移除了易出错的外部传入
resultObj参数,杜绝跨层级污染; - 显式检查
value !== null,避免null被误判为'object'; - 使用
Object.prototype.hasOwnProperty.call()替代obj.hasOwnProperty(),更健壮地规避原型链上同名方法覆盖风险; - 对递归返回的子对象执行
Object.keys().length > 0检查,确保空子树(如全被过滤掉的{ d: -3, e: { f: { g: -4 } } })不被挂载。
? 使用示例:
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 } } }⚠️ 注意事项:
- 该函数不处理数组(若需支持数组,请扩展判断
Array.isArray(value)并单独递归); -
filter回调函数应设计为纯函数,避免副作用; - 循环引用对象会导致无限递归,生产环境建议加入
WeakMap缓存检测机制。
掌握这种“分层构建 + 空结构剪枝”的递归模式,是实现可靠深度数据处理的基础能力。

















