
es-toolkit 函数式编程之 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-toolkitfilter是es-toolkit/fp模块中专为函数式管道设计的数组过滤操作符。它把Array.prototype.filter的能力封装为数据后置data-last的高阶函数先传入谓词predicate返回一个接收数组并产出过滤结果的函数直接嵌入pipe使用。与普通filter最大的不同在于它支持惰性求值在管道中与相邻的惰性操作如map、take融合成单趟遍历从而避免中间数组并支持提前短路。读完本文你将掌握es-toolkit/fp中filter的完整用法、类型收窄技巧以及其背后的推式惰性管道实现原理。一、filter 是什么为 pipe 而生的过滤操作符es-toolkit/fp是 es-toolkit 的函数式编程入口其所有函数都遵循「先配置、后数据」的调用形态。filter也不例外——它接收一个谓词函数返回一个「把readonly T[]变成过滤后数组」的函数const result pipe(array, filter(predicate));从源码可见filter.ts 的实现由两部分构成急切路径eager直接委托原生array.filter(predicate)用于filter单独调用、不在管道中参与融合的场景惰性路径lazy通过内部工具createLazyFunction构建推式变换用于在pipe中与相邻惰性函数融合。该辅助函数是es-toolkit/fp专属仅在需要把它作为pipe管道的一步时使用。通用非 fp场景请使用 src/array/filter.ts 中的常规版本。二、快速上手从管道中筛选元素filter会保留所有让predicate返回真值的元素。先看基本用法import { filter, pipe } from es-toolkit/fp; // 只保留偶数。 pipe( [1, 2, 3, 4], filter(x x % 2 0) ); // [2, 4]与原生Array.prototype.filter一致索引作为第二个参数传入谓词// 索引可作为第二参数使用。 pipe( [10, 20, 30, 40], filter((_value, index) index % 2 0) ); // [10, 30]上述两个用例与测试文件 filter.spec.ts 中的断言一一对应可直接在仓库中验证。三、类型谓词让结果类型自动收窄filter的类型签名做了重载处理见 filter.ts当谓词是类型守卫(value: T, index: number) value is S时返回函数类型为(array: readonly T[]) S[]结果元素类型被收窄为S当谓词是普通(value: T, index: number) boolean时返回(array: readonly T[]) T[]。利用这一点可以从混合类型数组中安全提取指定类型import { filter, pipe } from es-toolkit/fp; const result pipe( [1, a, 2, b], filter((x): x is string typeof x string) ); // result 被推断为 string[] 类型且值等于 [a, b]测试 filter.spec.ts 不仅断言了运行结果[a, b]还通过result.map(s s.toUpperCase())在类型层面验证了result确为string[]——若类型未收窄该行将无法通过编译检查。四、参数与返回值说明参数predicate(value: T, index: number) boolean对每个元素调用的函数返回true则保留该元素。若使用类型守卫value is S结果类型会相应收窄。返回值(array: readonly T[]) T[]把readonly T[]映射为过滤后数组的函数。使用类型守卫时结果为S[]。五、惰性求值原理推式管道与函数融合这是filter区别于普通实现的核心特性。文档明确说明filter是lazy-capable惰性兼容的在pipe中会与相邻的惰性操作融合逐元素地处理输入。5.1 底层基础设施惰性能力来自 src/fp/_internal/lazy.ts其设计要点如下SinkT接收上游推入的单个值返回false表示本次运行结束、不再接收更多值LazyTransform把下游Sink包装成上游Sink的变换函数这是pipe组合并驱动的惰性形态createLazyFunctionlazy.ts根据逐元素step构建LazyTransform。step接收(value, index, emit)其中emit把结果转发给下一阶段返回false可提前结束运行。内部用active标志防止短路后继续推值combineEagerAndLazyFunctionslazy.ts把急切实现与惰性变换配对通过Object.assign给函数挂上lazy与shortCircuit元数据。filter的惰性step非常简单谓词通过则emit(value)否则丢弃见 filter.ts。5.2 pipe 如何融合惰性函数pipe.ts 的实现分两步chunkFunctions把传入函数按「是否带lazy元数据」切分成连续分组pipe.ts对惰性分组且输入可迭代时调用lazyPipepipe.ts从最后一个函数开始逆向组合各变换最终用一个循环驱动输入数据逐元素流过整条推式管道一旦某个Sink返回false如take触发短路立即break剩余输入不再被访问。这意味着pipe([1..8], map(x x * x), filter(x x % 2 0), take(2))只会在前 4 个元素上计算平方不会为每一步构建中间数组。5.3 与 map、take 融合的实证map、take同样在 src/fp/array/ 中实现了惰性版本map的惰性step是emit(callback(value, index))见 map.tstake对非负整数count走惰性路径并以shortCircuit: true标记见 take.ts。测试 filter.spec.ts 用vi.fn对map与filter的谓词打桩并验证执行pipe([1, 2, 3, 4, 5, 6, 7, 8], map(mapSpy), filter(filterSpy), take(2)); // [4, 16]后mapSpy与filterSpy均只被调用 4 次——即map与filter被融合进同一次遍历且take(2)收集到 2 个结果后立即终止数组剩余部分从未被处理。六、进一步阅读管道入口与惰性求值的完整说明pipe函数式编程惰性基础设施源码src/fp/_internal/lazy.ts实现与类型重载src/fp/array/filter.ts行为验证测试src/fp/array/filter.spec.ts其余 fp 数组操作符src/fp/array/结合以上源码与测试你可以确信在pipe中连续使用map、filter、take等惰性操作符时es-toolkit 会以单趟、可短路的推式管道运行这也是该库在函数式链式调用场景下保持高效的关键设计。【免费下载链接】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),仅供参考