es-toolkit 兼容版 flowRight:Lodash 风格的右向左函数组合详解
【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit
flowRight是 es-toolkit 在 Lodash 兼容入口(es-toolkit/compat)中提供的函数组合工具,它把多个函数从右向左依次执行,前一函数的返回值作为后一函数的入参,最终生成一个新的复合函数。本文以仓库文档 docs/ja/compat/reference/function/flowRight.md 为骨架,结合源码与测试,系统讲解其用法、与flow的区别、数组展平特性、底层实现原理,以及官方推荐的现代替代方案。读完本文,你将能在数据转换管道中熟练选用合适的函数组合方式,并理解兼容版实现为何比现代版更复杂。
一、flowRight 是什么
flowRight创建一个新的函数,该函数会按从右到左的顺序依次执行给定的函数:最右侧的函数接收调用时传入的全部实参,其返回值再作为参数传给左侧的下一个函数,依此类推,直到最左侧的函数执行完毕并返回最终结果。
const combinedFunc = flowRight(...functions);它本质上等价于数学中的函数复合(composition):combined = f ∘ g ∘ h,即combined(x) = f(g(h(x)))。因此它执行顺序直观、易于理解,且与flow的执行方向正好相反,适合用来构建数据转换管道(data transformation pipeline)。
在 es-toolkit 中,flowRight存在两个入口:
| 入口 | 实现文件 | 定位 |
|---|---|---|
es-toolkit/compat | src/compat/function/flowRight.ts | 为兼容 Lodash 行为,支持数组传参与多层展平 |
es-toolkit/function | src/function/flowRight.ts | 现代精简实现,仅接受函数作为独立参数 |
本文主体聚焦于 compat(Lodash 兼容)版本。
二、安装与导入
es-toolkit 支持 npm 安装,然后从兼容入口导入:
npm install es-toolkitimport { flowRight } from 'es-toolkit/compat';对于只需要现代版本、不要求 Lodash 兼容性的场景,可改从函数子路径导入:
import { flowRight } from 'es-toolkit/function';三、基本用法
flowRight接受多个函数作为参数,从右向左依次执行。以下示例直接取自文档:
import { flowRight } from 'es-toolkit/compat'; // 基本用法 function add(x, y) { return x + y; } function square(n) { return n * n; } function double(n) { return n * 2; } // 右到左执行: double(square(add(x, y))) const calculate = flowRight(double, square, add); console.log(calculate(1, 2)); // double(square(add(1, 2))) = double(square(3)) = double(9) = 18执行过程拆解如下:
- 最右侧的
add(1, 2)先执行,得到3; square(3)执行,得到9;- 最左侧的
double(9)执行,得到最终结果18。
由于最右侧函数接收的是调用者传入的全部实参,flowRight复合函数本身可以接受任意数量的初始参数(如上面的x和y),而其余函数只接收上一个函数返回的单个值。
四、数组传参:Lodash 兼容的核心特性
与普通的函数组合不同,compat 版的flowRight允许以数组形式传入函数,这是为了保持与 Lodash 的_.flowRight行为一致。数组中的函数会被展平后再参与组合:
// 数组传参 const calculate2 = flowRight([double, square], add); console.log(calculate2(2, 3)); // 50这里[double, square]被展平为double, square,与add一起组合,等价于double(square(add(2, 3))) = double(25) = 50。
展平能力来自实现中对 flatten 的调用。查看 src/compat/function/flowRight.ts 的实现:
export function flowRight(...funcs: Array<Many<(...args: any[]) => any>>): (...args: any[]) => any { const flattenFuncs = flatten(funcs, 1); if (flattenFuncs.some(func => typeof func !== 'function')) { throw new TypeError('Expected a function'); } return flowRightToolkit(...flattenFuncs); }其中参数类型Many<T>定义在 src/compat/_internal/Many.ts:
export type Many<T> = T | readonly T[];即每个位置既可以是单个函数,也可以是函数数组。flatten(funcs, 1)表示只展平一层(深度为 1),因此像flowRight([[f1, f2], f3])这种嵌套两层的情况仍会保留内层数组,这沿用了 Lodash 的展平语义。
参数校验与异常
展平之后,实现会逐一检查每个元素是否为函数,一旦发现非函数值(如null、数字、字符串等),立即抛出TypeError('Expected a function')。这一点在测试 src/compat/function/flowRight.spec.ts 中有明确验证:
it(`\`flowRight\` should throw an error if a function is not passed`, () => { expect(() => { flowRight(null as any); }).toThrow(); });参数与返回值
| 项目 | 说明 |
|---|---|
参数...functions | Array<Function \| Function[]>:从右到左执行的函数,支持以数组形式传入 |
| 返回值 | Function:一个新的复合函数,调用时按从右到左顺序执行全部函数 |
五、与 flow 的执行方向对比
flowRight与flow互为镜像:flow从左到右执行,flowRight从右到左执行。以add → square → double三个函数为例:
// flow: 从左到右,add(1,2) -> square(3) -> double(9) // flowRight: 从右到左,add(1,2) -> square(3) -> double(9),但书写顺序相反 const viaFlow = flow(add, square, double); const viaFlowRight = flowRight(double, square, add); console.log(viaFlow(1, 2)); // 18 console.log(viaFlowRight(1, 2)); // 18两者最终的计算结果相同,但参数书写顺序完全相反,因此flowRight更贴近double(square(add(x, y)))的自然阅读习惯(先出现的函数包裹在外层)。当某个函数的实参个数多于 1 个时,flow与flowRight都会把调用时的全部实参交给第一个(方向上的第一个)执行的函数。
六、现代替代方案(官方推荐)
compat 版flowRight因需要兼容 Lodash 的数组展平行为而变得复杂。官方文档在函数说明前专门放置了警告(warning)区块,建议优先使用更快速、更现代的 es-toolkit 原生版 flowRight。
原生版实现极简(见 src/function/flowRight.ts):
export function flowRight(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any { return flow(...funcs.reverse()); }它只是把参数数组反转后交给flow。而flow的实现(见 src/function/flow.ts)也相当简洁:
export function flow(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any { return function (this: any, ...args: any[]) { let result = funcs.length ? funcs[0].apply(this, args) : args[0]; for (let i = 1; i < funcs.length; i++) { result = funcs[i].call(this, result); } return result; }; }两个关键细节:
- 返回全新的函数:
flowRight/flow不会修改或直接返回原函数,而是生成一个新的复合函数。测试 src/function/flowRight.spec.ts 验证了这一点:flowRight(noop)的结果!== noop。 this上下文透传:复合函数被调用时的this会通过apply/call传递给内部每个函数。原生版文档 docs/reference/function/flowRight.md 给出了利用this的示例:
import { flowRight } from 'es-toolkit/function'; const context = { multiplier: 3, }; function multiply(this: typeof context, x: number) { return x * this.multiplier; } const add = (x: number) => x + 10; const combined = flowRight(multiply, add).bind(context); console.log(combined(5)); // 45 // 执行顺序: add(5) = 15, multiply(15) = 45注意:原生版
flowRight只接受独立函数参数,不支持数组传参,也不包含TypeError校验,因此不要将 compat 版的数组用法直接迁移到es-toolkit/function入口。
不使用库的等价写法
对于简单场景,文档也给出了不使用库的等价实现,作为现代替代方案:
// 现代替代(推荐) const modernCalculate = (x, y) => double(square(add(x, y))); console.log(modernCalculate(1, 2)); // 18或者使用函数链式调用:
const chainedCalculate = (x, y) => [x, y] .reduce((acc, val, idx) => idx === 0 ? val : acc + val) .valueOf() |> (n => n * n) |> (n => n * 2);七、与柯里化等函数式工具的组合
compat 版flowRight可以与其他函数式工具(如curry、ary、head、uniq)组合使用,这在测试 src/compat/function/flowRight.spec.ts 中有完整覆盖:
- 柯里化函数:
flowRight(curried, head)可以正常工作,其中curried = curry((i) => i),对[1]调用返回1; - 带占位符的柯里化函数:
flowRight(uniq, getProp)配合curry(ary(map, 2), 2)生成的getProp,可以从对象数组中提取去重后的属性值[1, 2]; - 返回值透传:
flowRight(fixed, square, add)中square的返回值9被传给fixed(n.toFixed(1)),最终得到字符串'9.0'。
这些用例说明 compat 版flowRight与柯里化工具组合时行为与 Lodash 保持一致,可直接作为从 Lodash 迁移时的替代品。
八、源码级原理小结
梳理完整的调用链如下:
es-toolkit/compat 的 flowRight └─ flatten(funcs, 1) // 一层展平,兼容数组传参(src/compat/function/flowRight.ts) └─ 校验全部为函数,否则抛 TypeError('Expected a function') └─ 委托给 es-toolkit/function 的 flowRight └─ flow(...funcs.reverse()) // 反转顺序后从左到右执行(src/function/flowRight.ts) └─ 返回新函数,内部用 apply/call 依次调用(src/function/flow.ts)也就是说,compat 版本在原生版本之上额外增加了「展平」与「类型校验」两层逻辑,这正是文档警告其「复杂」的原因。在不需要 Lodash 数组传参语义的新项目中,直接使用 es-toolkit/function 的 flowRight 可以获得更小、更快的实现。
九、使用建议
- 新项目优先用原生版:从
es-toolkit/function导入flowRight,代码更简洁、性能更好; - Lodash 迁移项目用 compat 版:从
es-toolkit/compat导入,可无缝替换_.flowRight,保留数组传参行为; - 牢记方向性:
flow从左到右、flowRight从右到左,混用时容易因书写顺序不同产生结果差异; - 避免把数组传给原生版:原生版不支持展平,传数组会被当作单个函数导致运行时错误;
- 合理利用
this透传:复合函数可绑定上下文,内部函数通过this访问外部状态。
【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考