ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

es-toolkit 的 omitBy 兼容实现解析:按谓词动态过滤对象属性的完整指南

es-toolkit 的 omitBy 兼容实现解析:按谓词动态过滤对象属性的完整指南 es-toolkit 的 omitBy 兼容实现解析按谓词动态过滤对象属性的完整指南【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkitomitBy是 es-toolkit 提供的对象属性过滤工具对对象的每个属性执行谓词函数凡是谓词返回true的属性都会被剔除最终返回一个只包含不满足条件属性的新对象。本文以 compat 兼容版文档 为核心骨架结合 src/compat/object/omitBy.ts 源码与 src/compat/object/omitBy.spec.ts 测试用例完整讲解其用法、参数语义、边界行为、底层实现原理并与更快的现代版es-toolkit/object进行对比帮助你按需选择正确的 API。注意本文讲解的omitBy来自es-toolkit/compat入口旨在提供与 Lodash 行为高度一致的兼容实现如果你不需要 Lodash 兼容语义官方强烈推荐使用更快、更现代的es-toolkit/object版本见文末对比小节。一、omitBy 解决什么问题在业务开发中经常需要按条件剔除属性比如删除对象中所有字符串类型的值、剔除所有空字符串、按 key 前缀过滤配置项等。omitBy正是为此设计的——它接收一个源对象和一个谓词函数predicate遍历对象每个属性将谓词返回true的属性从结果中剔除const result omitBy(obj, predicate);与pickBy保留满足条件的属性相反omitBy保留的是不满足条件的属性二者互为镜像。它在需要根据运行时条件动态过滤对象时非常有用无需预先枚举要删除的 key。二、安装与导入本项目是 monorepo 形态的开源仓库使用 Yarn 管理依赖见仓库根目录 package.json 与yarn.lock。在业务项目中安装 es-toolkit 后按入口导入// 兼容版Lodash 互換语义与 Lodash 对齐 import { omitBy } from es-toolkit/compat; // 现代版更快的原生实现 import { omitBy } from es-toolkit/object;两条入口都导出了同名omitBy但行为存在差异见第五节与第九节请根据实际需求选择。三、基础用法五个典型场景原文档给出了 5 个覆盖不同谓词形态的示例全部继承如下3.1 删除特定类型的值import { omitBy } from es-toolkit/compat; const data { a: 1, b: remove, c: 3, d: keep }; const numbers omitBy(data, value typeof value string); // 结果: { a: 1, c: 3 }3.2 按真值条件删除剔除所有假值const user { id: 1, name: John, age: 0, active: false, email: }; const validData omitBy(user, value !value); // 结果: { id: 1, name: John }age: 0、active: false、email: 均为假值被剔除3.3 按 key 名过滤谓词除了接收 value还会接收属性名 key因此可以基于 key 做过滤const settings { userSetting: true, adminSetting: false, debugMode: true }; const userOnly omitBy(settings, (value, key) key.startsWith(admin)); // 结果: { userSetting: true, debugMode: true }3.4 混合对象中剔除数值属性const mixed { str: hello, num1: 42, bool: true, num2: 0, obj: {} }; const noNumbers omitBy(mixed, value typeof value number); // 结果: { str: hello, bool: true, obj: {} }3.5 对数组使用数组是特殊的对象索引为 keyomitBy同样适用结果会以索引字符串为 key的对象形式返回const arr [1, 2, 3, 4, 5]; const filtered omitBy(arr, value value % 2 0); // 结果: { 0: 1, 2: 3, 4: 5 }值为奇数、索引为 0/2/4 的属性被保留3.6 同时使用 value、key 与源对象虽然类型签名只声明了两个参数但兼容版实现实际会以三个参数调用谓词见源码 L95predicate(value, key, object)因此你可以在谓词中拿到原始源对象做统计或对照const scores { math: 90, science: 75, english: 85, art: 60 }; const passingGrades omitBy(scores, (value, key, obj) { console.log(${key}: ${value} (平均: ${Object.values(obj).reduce((a, b) a b) / Object.keys(obj).length})); return value 80; }); // 结果: { math: 90, english: 85 }四、边界处理null 与 undefinedomitBy对null或undefined源对象采取宽容策略——将其视为空对象处理返回{}而不是抛错import { omitBy } from es-toolkit/compat; omitBy(null, () true); // {} omitBy(undefined, () true); // {}这一点在源码中体现得非常直接实现的第一行就是空值短路src/compat/object/omitBy.tsif (object null) { return {}; }注意这里用的是宽松相等 null因此同时覆盖了null和undefined两种情况。对应的测试用例位于 omitBy.spec.ts当源对象为null时无论谓词为何结果均为{}。五、参数与返回值详解参数参数类型说明objectRecordstring, T \| Recordnumber, T \| object \| null \| undefined待过滤的源对象支持字符串键对象、数值键对象、数组、普通对象以及null/undefinedpredicateValueKeyIterateeT[keyof T] \| ValueKeyIterateeT可选对每个属性执行的谓词函数返回true的属性将被剔除默认值为identity函数即原样返回输入值predicate是可选的。若省略会退化为默认的identity谓词——此时等价于保留所有假值属性、剔除所有真值属性。这一默认值在实现中通过createIteratee(shouldOmit ?? identity)生效src/compat/object/omitBy.tsidentity定义于 src/compat/function/identity.ts。测试中专门覆盖了该场景omitBy({ a: 1, b: omit, c: 3 }, null)返回{}omitBy.spec.ts——因为null谓词被?? identity兜底为恒等函数后三个属性的值均为真值于是全部被剔除。返回值Recordstring, S | Recordnumber, S | PartialT由所有谓词返回 false不满足条件的属性构成的新对象。函数不会修改原对象始终返回全新的对象。谓词的类型ValueKeyIteratee兼容版的谓词类型来自ValueKeyIterateeT定义于 src/compat/_internal/ValueKeyIteratee.tsexport type ValueKeyIterateeT ((value: T, key: string) unknown) | IterateeShorthandT;它可以是函数(value, key) unknown最常用IterateeShorthand 简写PropertyKey | [PropertyKey, any] | PartialShallowT即属性名、[属性名, 值]二元组或部分对象。这得益于实现内部统一通过createIteratee即 src/compat/util/iteratee.ts 中的iteratee转换器把任意形态的谓词归一为函数转换规则如下函数原样返回属性名 / Symbol / 数值 key转换为property(key)即取出该属性的值[属性名, 值]二元组转换为matchesProperty即判断该属性是否等于指定值普通对象转换为matches即判断源对象是否匹配该部分对象null/undefined返回identity。因此omitBy的谓词既可以是回调函数也可以直接传入active、[type, admin]或{ status: disabled }这类 Lodash 风格简写——这正是兼容版与 Lodash 语义对齐的体现。六、源码实现深度解析兼容版做了什么兼容版omitBy的完整实现位于 src/compat/object/omitBy.ts核心逻辑只有十几行export function omitByT, S extends T( object: Recordstring, T | Recordnumber, T | object | null | undefined, shouldOmit?: ValueKeyIterateeT[keyof T] | ValueKeyIterateeT ): Recordstring, S | Recordnumber, S | PartialT { if (object null) { return {}; } const result: PartialT {}; const predicate createIteratee(shouldOmit ?? identity); const keys [...keysIn(object), ...getSymbolsIn(object)] as Arraykeyof T; for (let i 0; i keys.length; i) { const key (isSymbol(keys[i]) ? keys[i] : keys[i].toString()) as keyof T; const value object[key as keyof typeof object]; if (!predicate(value, key, object)) { result[key] value; } } return result; }关键点有三6.1 键的收集keysIn getSymbolsIn与简单实现只用Object.keys不同兼容版拼接了两个来源keysIn(object)src/compat/object/keysIn.ts返回自身 原型链上所有可枚举字符串键含继承属性。它对非对象值会先装箱Object(object)对数组/类数组对象按索引展开对原型对象会剔除constructor。getSymbolsIn(object)src/compat/_internal/getSymbolsIn.ts沿原型链逐层收集所有 Symbol 键while (object) { ...; object Object.getPrototypeOf(object); }。正因为如此兼容版omitBy能够处理继承属性和Symbol 键属性这是它与现代版最本质的实现差异现代版只用Object.keys见 src/object/omitBy.ts。6.2 键的归一化与 -0 符号保留遍历时非 Symbol 键统一调用.toString()转为字符串Symbol 键保持原样isSymbol判定来自 src/compat/predicate/isSymbol.ts。测试用例 omitBy.spec.ts 验证了一个微妙行为-0与0作为键时符号会被保留——{ -0: a, 0: b }经过omitBy过滤后-0键与0键不会互相串扰。6.3 保留条件!predicate(...)循环体内只有一行过滤逻辑if (!predicate(value, key, object)) { result[key] value; }。谓词返回假值时属性被保留返回真值时被剔除。注意谓词以(value, key, object)三个实参被调用——第三个参数object正是源对象这解释了 3.6 节示例中能在谓词内访问obj的原因。七、测试用例揭示的兼容语义src/compat/object/omitBy.spec.ts 是理解兼容版行为边界的最好教材除前文已述的用例null 源对象、null 谓词、-0/0符号外还覆盖了继承属性被纳入过滤L28-L35Foo.prototype object后new Foo()的实例属性连同原型上的属性一起参与谓词过滤结果与直接过滤源对象一致Symbol 键参与过滤且不可枚举 Symbol 不进入结果L47-L109自身 Symbol、原型链上的可枚举 Symbol 都会被遍历并参与谓词判断而通过Object.defineProperty定义为enumerable: false的 Symbol 不会出现在结果中symbol3 in actual为false数组对象按索引过滤L111-L114omitBy([1, 2, 3], ...)返回{ 1: 2 }与文档 3.5 节的示例行为一致带数字length属性的普通对象不会被误判为类数组L129-L146{ level: error, message: hi, length: 104, empty: undefined }配合isNil过滤时length: 104作为普通属性被保留同时 Symbol 键属性也完好保留。这些行为共同保证了与 Lodash 的omitBy语义高度一致这正是es-toolkit/compat入口存在的意义。八、性能提示为什么文档推荐现代版原文档开头给出了明确的警告请优先使用 es-toolkit 的现代版omitBydocs/reference/object/omitBy.md理由是兼容版相对较慢慢的来源正是本文分析的三个环节类数组对象的检查keysIn内部需要先判断isArrayLike、isPrototype、isBuffer、isTypedArray等src/compat/object/keysIn.ts存在额外分支开销iteratee 转换谓词要经过createIteratee的简写归一化函数/属性名/二元组/部分对象的分派比直接调用回调函数多一层间接键的转换过程遍历时需要对每个 key 执行isSymbol判断与.toString()转换还要额外收集原型链与 Symbol 键。而现代版实现src/object/omitBy.ts只做最朴素的事Object.keys(obj)取自身可枚举字符串键 → 循环调用shouldOmit(value, key)→ 收集结果无继承属性、无 Symbol、无 iteratee 简写、无类型转换。如果不需要 Lodash 兼容语义不依赖继承属性、Symbol 键、-0符号或简写谓词应使用es-toolkit/object的版本以获得更好的性能只有迁移 Lodash 代码、需要行为完全一致时才使用es-toolkit/compat。九、快速选型总结维度es-toolkit/compat的 omitByes-toolkit/object的 omitBy导入入口import { omitBy } from es-toolkit/compatimport { omitBy } from es-toolkit/object遍历范围自身 原型链可枚举键 Symbol 键仅自身可枚举字符串键谓词形态函数 / 属性名 /[key, value]/ 部分对象iteratee 简写仅函数谓词参数(value, key, object)(value, key)null/undefined源返回{}——类型上要求对象默认谓词identity必须显式传入性能相对较慢类数组检查 iteratee 转换 键转换更快最小化实现适用场景从 Lodash 迁移、需要完全兼容语义新项目、追求性能总之omitBy是反向过滤的对象工具谓词返回true即剔除。默认场景推荐现代版需要 Lodash 级兼容行为时理解keysIngetSymbolsIncreateIteratee这套兼容管线你就能准确预测它在继承属性、Symbol、-0、length属性等边界输入下的行为。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表