资讯动态

es-toolkit 的 Iterator 版 filter:基于原生 Iterator.prototype.filter 的惰性筛选与 pipe 组合指南

发布时间:2026/9/17 2:19:24 来源:尧图企业网站定制
es-toolkit 的 Iterator 版 filter基于原生 Iterator.prototype.filter 的惰性筛选与 pipe 组合指南【免费下载链接】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-toolkites-toolkit/fp/iterator提供的filter用于创建一个“只保留满足条件的元素”的惰性迭代器转换函数专为与函数式编程的pipe组合而设计。本文以 docs/ja/iterator/reference/filter.md 为核心结合 src/fp/iterator/filter.ts 的源码实现与类型重载讲解它的参数语义、返回值、类型收窄能力、底层委托原理以及它与数组版filter、原生Iterator.prototype.filter的使用边界帮助你写出既符合函数式风格又保持类型安全的管道代码。为什么需要es-toolkit/fp/iterator版filter现代 JavaScript 已经原生提供了Iterator.prototype.filter可以直接写出source.filter(predicate)。但在函数式组合的场景中我们希望把转换步骤作为一等函数传入pipe让每一步都是“接收迭代器、返回新迭代器”的纯函数而不是在迭代器实例上链式调用方法。这正是es-toolkit/fp/iterator的定位。filter返回的不是筛选后的结果而是一个函数它接收一个IteratorT返回一个惰性求值的IteratorObject。典型用法如下const result pipe(source, filter(predicate));import { pipe } from es-toolkit/fp; import { filter, toArray } from es-toolkit/fp/iterator; // 只保留偶数 pipe( [1, 2, 3, 4].values(), filter(x x % 2 0), toArray() ); // 结果: [2, 4]管道中的filter与toArray各司其职filter负责惰性筛选toArray负责把最终的迭代器物化为数组。如果你只是在普通代码里做一次性筛选官方文档的建议是直接使用原生Iterator.prototype.filter只有在用pipe串联多个转换时才需要切换到es-toolkit/fp/iterator这个变体。filter(predicate)的完整签名参数predicate(value: T, index: number) unknown对每个元素及其索引调用。当返回值被判定为真值truthy时该元素会被保留返回假值falsy则被丢弃。注意predicate的返回值类型是unknown而非boolean这与原生filter的“truthy/falsy 判定”语义保持一致任何能被隐式转换为真值的返回值都会保留元素。返回值(source: IteratorT) IteratorObjectT, undefined一个把IteratorT映射为“惰性生成保留元素”的IteratorObject的函数。关键点在于惰性lazyfilter(predicate)并不会立刻遍历源迭代器只有当下游真正开始消费例如调用toArray()或for...of时元素才会被逐个取出并经过predicate判定。这意味着它与map、take等组合时可以做到“边走边筛、提前终止”详见后文。源码实现一行委托给原生Iterator.prototype.filter打开 src/fp/iterator/filter.ts 可以看到实现非常精简export function filterT( predicate: (value: T, index: number) unknown ): (source: IteratorT) IteratorObjectT, undefined { return function filterInIterator(source: IteratorT): IteratorObjectT, undefined { return Iterator.from(source).filter(predicate) as IteratorObjectT, undefined; }; }其核心只有一行return Iterator.from(source).filter(predicate);这里的实现策略可以拆解为两层标准化源迭代器Iterator.from(source)是 ES 标准库方法它把任意符合迭代器协议的对象统一包装为标准Iterator实例保证后续可以安全调用.filter()。委托原生筛选实际的筛选逻辑完全交给原生Iterator.prototype.filter。也就是说es-toolkit/fp/iterator的filter并没有重新实现一套筛选算法而是把“惰性 类型判定”的底层行为交由引擎原生能力承担自身只负责柯里化适配把predicate与source拆成pipe友好的两段式调用。这种“薄封装”设计的直接收益是性能与原生方法对齐且天然继承原生filter的惰性求值语义。从源码结构看这也是es-toolkit/fp/iterator系列index.ts 中导出的filter、map、take、takeWhile等的统一模式。类型重载普通谓词与类型守卫filter提供了两个重载对应两种类型行为// 重载一谓词是类型守卫元素类型被收窄为 S export function filterT, S extends T( predicate: (value: T, index: number) value is S ): (source: IteratorT) IteratorObjectS, undefined; // 重载二普通谓词元素类型保持不变 export function filterT( predicate: (value: T, index: number) unknown ): (source: IteratorT) IteratorObjectT, undefined;当predicate写成类型守卫形式(value): value is S时TypeScript 会把产出迭代器的元素类型自动收窄为S。这一点让filter兼具“运行时筛选”和“编译期类型过滤”双重能力例如import { pipe } from es-toolkit/fp; import { filter, toArray } from es-toolkit/fp/iterator; const mixed: Iteratornumber | string [1, a, 2, b].values(); const strings pipe( mixed, filter((x): x is string typeof x string), toArray() ); // strings: string[]后续可以直接调用字符串方法而无需再次断言与数组版filter的对比同一 API 形态不同数据源es-toolkit的 fp 模块同样为数组提供了filter位于 src/fp/array/filter.ts签名形态完全一致接收predicate返回接收数组的函数但数据源与产出不同维度es-toolkit/fp/iterator的filteres-toolkit/fp数组版filter输入IteratorTreadonly T[]输出惰性的IteratorObjectT立即求值的T[]求值时机消费时才执行predicate调用时立即执行底层实现委托原生Iterator.prototype.filter自实现数组筛选见 src/fp/array/filter.ts数组版对应测试 src/fp/array/filter.spec.ts 验证了它的行为契约只保留通过谓词的元素[1, 2, 3, 4]过滤偶数得到[2, 4]predicate的第二个参数是索引(_value, index) index % 2 0保留偶数位元素类型守卫可收窄结果类型(x): x is string得到string[]没有任何元素匹配时返回空数组。选择哪个版本取决于你是在“管道中处理数组”还是“管道中处理迭代器”前者用es-toolkit/fp的filter后者用es-toolkit/fp/iterator的filter。惰性求值与管道融合一次遍历、提前终止迭代器版filter的最大实战价值在于惰性带来的融合fusion效果。由于filter返回的是惰性迭代器当它处于pipe中间时整个管道不会为每个步骤分别遍历一遍数据而是对每个元素“边流经各步骤边判断”并且可以在下游提前终止时停止上游生产。虽然 src/fp/array/filter.spec.ts 中的融合用例是针对数组版验证的但它揭示的管道语义同样适用于迭代器版map、filter、take串成的管道mapSpy与filterSpy都只被调用了 4 次而不是 8 次因为take(2)拿到前两个合格结果后就终止了整条流水线。把同样的思路用在迭代器版上你可以构建出“无需物化中间数组”的长管道import { pipe } from es-toolkit/fp; import { filter, map, take, toArray } from es-toolkit/fp/iterator; // 对 1 到 100 的迭代器求平方 → 筛偶数 → 取前 3 个 const result pipe( range(1, 101).values(), // 伪代码示意任意迭代器数据源 map(x x * x), filter(x x % 2 0), take(3), toArray() );由于每一步都保持惰性源迭代器最多只会被推进到产生 3 个合格结果所需的元素数而不是先完整算完 100 个平方数再筛选。使用建议何时选原生、何时选本函数结合官方文档的提示与源码实现可以总结出清晰的选择规则普通代码、单次筛选直接用原生source.filter(predicate)无需额外依赖性能最优。用pipe组合多个转换使用es-toolkit/fp/iterator的filter让每一步都以“接收迭代器、返回迭代器”的纯函数形态接入管道代码可读性与可组合性最佳。需要类型收窄两种方式都支持类型守卫但本函数的柯里化形态配合pipe时类型信息能在整条管道中正确流动。filter还可以与 src/fp/iterator/index.ts 中同系列的其他函数map、take、takeWhile、dropWhile、partition、uniqBy、zip、count、scan等自由组合构成完整的惰性数据处理工具箱。小结es-toolkit/fp/iterator的filter是一个“薄而准”的函数式适配层它以柯里化形态把原生Iterator.prototype.filter接入pipe管道通过Iterator.from保证任意迭代器源的兼容性通过双重重载在编译期为类型守卫提供收窄能力并以惰性求值天然支持管道融合与提前终止。对于任何需要在函数式管道中处理无限或大型迭代数据流的场景它都是衔接es-toolkit/fp与 ES 原生迭代器能力的关键一环。官方文档日文docs/ja/iterator/reference/filter.md官方文档英文docs/iterator/reference/filter.md源码实现src/fp/iterator/filter.ts同系列导出src/fp/iterator/index.ts数组版对比实现src/fp/array/filter.ts数组版行为测试src/fp/array/filter.spec.tspipe使用指南docs/ja/fp/reference/pipe.md【免费下载链接】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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价