
es-toolkit/fp 的 orderBy 函数式排序指南在 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-toolkit导读es-toolkit/fp模块提供了面向函数式编程data-last 风格的工具函数其中orderBy用于创建一个「根据多个条件与排序方向对对象数组排序」的函数。本文将围绕 docs/ja/fp/reference/orderBy.md 展开讲解该函数在pipe管道中的典型用法、参数与返回值语义并结合src/fp/array/orderBy.ts、src/array/orderBy.ts与src/_internal/compareValues.ts的源码剖析其底层实现原理。读完本文你将能在自己的pipe数据流中自由组合多条件排序并理解它与普通版orderBy的差异与选型依据。一、为什么需要 fp 版的 orderBy普通版orderBy的调用形态是「数组在前」orderBy(arr, criteria, orders)一次性接收数组并返回排序结果。而es-toolkit/fp的全部函数都采用data-last数据置后设计先接收配置参数返回一个等待数据传入的函数。这样每个函数都能作为pipe管道中的一个环节。文档给出的标准形态如下const result pipe(array, orderBy(criteria, orders));也就是说orderBy(criteria, orders)本身返回(array: readonly T[]) T[]由pipe把待排序的数组喂给它。从源码可以看到这一层包装非常薄本质是对主库函数的柯里化封装src/fp/array/orderBy.tsexport function orderByT extends object( criteria: ReadonlyArray((item: T) unknown) | keyof T, orders: ReadonlyArrayasc | desc ): (array: readonly T[]) T[] { return function (array: readonly T[]): T[] { return orderByToolkit(array, criteria, orders); }; }从源码结构可以看出fp 版并不重复实现排序逻辑而是在闭包中记住criteria与orders真正执行时把数组转交给 src/array/orderBy.ts 中的主库orderBy。这也保证了两种版本的行为完全一致。二、基本用法在 pipe 中按单一条件排序文档中的入门示例是按age字段升序排列用户数组import { orderBy, pipe } from es-toolkit/fp; const users [ { name: a, age: 2 }, { name: b, age: 1 }, ]; pipe(users, orderBy([age], [asc])); // [{ name: b, age: 1 }, { name: a, age: 2 }]这里orderBy([age], [asc])先被求值得到一个「接收数组并返回排序后新数组」的函数pipe再把users从左到右依次传给管道中的每个函数。这一示例同样出现在单元测试 src/fp/array/orderBy.spec.ts 中用于验证pipe组合的正确性。三、参数与返回值详解文档明确给出了orderBy的完整签名criteriaArray((item: T) unknown) | keyof T用于比较的对象键或选择器函数。既可以直接写属性名如age也可以传返回任意值的函数如obj obj.user两者可以混用。ordersArrayasc | desc与criteria一一对应的排序方向。asc表示升序desc表示降序。返回值(array: readonly T[]) T[]一个将readonly T[]映射为新的已排序数组的函数。两个数组在类型上被声明为ReadonlyArray这意味着配置在创建后不应被修改排序函数对输入的readonly数组也完全只读不会原地改动原数组见下文实现分析。四、多条件复合排序与方向复用orderBy的核心价值在于复合排序当第一个条件比较结果相等时继续使用下一个条件决定次序。这一点在原文档与主库文档 docs/reference/array/orderBy.md 中均有说明主库文档给出了更完整的示例import { orderBy } from es-toolkit/array; const users [ { user: fred, age: 48 }, { user: barney, age: 34 }, { user: fred, age: 40 }, { user: barney, age: 36 }, ]; orderBy(users, [obj obj.user, age], [asc, desc]); // [ // { user: barney, age: 36 }, // { user: barney, age: 34 }, // { user: fred, age: 48 }, // { user: fred, age: 40 } // ]可以看到先按user升序barney排在fred前同组内再按age降序所以barney组中 36 排在 34 前fred组中 48 排在 40 前。属性名与选择器函数可以混合使用。另一个值得注意的语义是orders 数量不足时最后一个方向被复用。主库文档中的例子orderBy(data, [a, b, c], [asc, desc]); // a 升序b 与 c 均按降序这一行为在 src/array/orderBy.ts 的实现中可以得到验证const ordersLength orders.length; for (let i 0; i criteria.length; i) { const order ordersLength i ? orders[i] : orders[ordersLength - 1]; const criterion criteria[i]; const criterionIsFunction typeof criterion function; const valueA criterionIsFunction ? criterion(a) : a[criterion]; const valueB criterionIsFunction ? criterion(b) : b[criterion]; const result compareValues(valueA, valueB, order); if (result ! 0) { return result; } } return 0;实现细节值得逐点拆解不修改原数组先用arr.slice()复制一份再在副本上sort因此返回的是新数组原数组保持不变。稳定且可组合的比较循环依次取出每个criterion与对应的order。若criteria数量多于orders超出部分全部使用最后一个方向orders[ordersLength - 1]。键与函数统一处理typeof criterion function时调用函数取值否则直接读取a[criterion]属性。短路返回一旦compareValues返回非零即两个元素在该条件下可分出先后立即作为本次比较结果返回只有全部条件都相等时才返回0此时sort保持两个元素的相对顺序。五、底层比较语义compareValues 对 null / undefined 的处理排序的最终裁决由 src/_internal/compareValues.ts 完成。它定义了清晰的空值语义普通值权重为0null权重为1undefined权重为2因此升序时普通值 nullundefined同类空值之间视为相等降序并不是独立实现而是「升序比较时交换两个操作数」compareAscending(b, a)这与 lodash 等库的常见策略一致。export function compareValues(a: any, b: any, order: asc | desc): 0 | -1 | 1 { return order asc ? compareAscending(a, b) : compareAscending(b, a); }这意味着即使对象某些字段缺失值为undefined排序也不会崩溃空值会被稳定地推到升序序列的末尾适合处理来自外部数据源的不完整对象。六、与普通版 orderBy 的选型建议原文档给出了一条明确的选型指引普通代码非管道组合中推荐直接使用主库的orderBy当需要用pipe串联变换时才使用 fp 版。因为普通版直接接收数组少一层柯里化包装调用更直接而 fp 版的价值在于「配置一次、数据后到」可以像其他 fp 操作符一样自由嵌入管道。fp 版还可与es-toolkit/fp的其他函数自然衔接例如先filter再orderByimport { filter, orderBy, pipe } from es-toolkit/fp; const result pipe( users, filter(u u.age 18), orderBy([age], [desc]) );pipe会将函数按从左到右的顺序依次应用于数据见 src/fp/pipe.ts 与 docs/fp/reference/pipe.md无需中间变量代码自上而下与执行顺序一致可读性更好。七、总结es-toolkit/fp 的orderBy通过 contenteditable="false">【免费下载链接】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),仅供参考