
es-toolkit/fp 函数式 sortBy以 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 函数式模块es-toolkit/fp中的sortBy讲解如何用它创建按一个或多个条件升序排序的纯函数并与pipe组合实现数据流式处理。读完本文你将掌握sortBy的参数签名、多键/选择器函数的用法、底层排序原理委托orderBy与compareValues的比较逻辑以及它与普通es-toolkit/array版sortBy的取舍。一、背景为什么需要 fp 版的 sortByes-toolkit 同时提供了两套 API普通命令式如es-toolkit/array中的sortBy(arr, criteria)与 函数式 fp 模块es-toolkit/fp。两者功能一致但参数顺序与调用形态不同普通版sortBy(arr, criteria)—— 数据在前配置在后一次性完成排序。fp 版sortBy(criteria)—— 先接收配置排序条件返回一个等待数据的函数即>const result pipe(array, sortBy(criteria));fp 版的返回值签名是(array: readonly T[]) T[]恰好是 pipe 中操作符函数的形态pipe把初始值从左到右依次穿过每个函数前一个函数的输出作为后一个函数的输入源码见 src/fp/pipe.ts。因此sortBy(criteria)可以像map(fn)、filter(fn)一样直接嵌入管道与其他变换自然组合。官方文档明确建议普通代码优先使用原版sortBy只有当你需要借助pipe组合一系列变换时才使用 fp 变体。二、基本用法单键、多键与选择器函数sortBy按升序排列对象数组。每个 criterion排序条件可以是对象键或返回待比较值的函数当两个元素在当前条件上并列时使用下一个条件打破平局。排序是稳定的stable且不会修改输入数组。import { pipe, sortBy } from es-toolkit/fp; const users [ { user: foo, age: 24 }, { user: bar, age: 7 }, { user: foo, age: 8 }, { user: bar, age: 29 }, ]; // 按单个键排序。 pipe(users, sortBy([age])); // [{ user: bar, age: 7 }, { user: foo, age: 8 }, { user: foo, age: 24 }, { user: bar, age: 29 }] // 按多个条件排序用下一个条件打破平局。 pipe(users, sortBy([user, age])); // [{ user: bar, age: 7 }, { user: bar, age: 29 }, { user: foo, age: 8 }, { user: foo, age: 24 }] // 也可以用选择器函数代替键。 pipe(users, sortBy([item item.age]));参数criteriaArray((item: T) unknown) | keyof T用于比较的对象键和/或选择器函数按顺序依次应用。类型约束为T extends object即排序目标是对象数组。返回值(array: readonly T[]) T[]一个将readonly T[]映射为新的、已排序T[]的函数。三、源码剖析一层柯里化包装 委托核心排序fp 版sortBy的实现非常精简本质是对普通版的一层配置先行包装。完整源码见 src/fp/array/sortBy.tsimport { sortBy as sortByToolkit } from ../../array/sortBy.ts; export function sortByT extends object( criteria: ReadonlyArray((item: T) unknown) | keyof T ): (array: readonly T[]) T[] { return function (array: readonly T[]): T[] { return sortByToolkit(array, criteria); }; }外层函数只负责记住criteria返回的闭包在收到数组时才真正调用底层实现 src/array/sortBy.ts。而普通版本身又是一个薄壳把排序方向固定为升序后直接委托给更通用的orderBy// src/array/sortBy.ts export function sortByT extends object( arr: readonly T[], criteria: ReadonlyArray((item: T) unknown) | keyof T ): T[] { return orderBy(arr, criteria, [asc]); }因此完整的调用链是fp/sortBy(criteria)→array/sortBy(arr, criteria)→orderBy(arr, criteria, [asc])。多条件排序的逐条比较逻辑集中在 src/array/orderBy.tsreturn arr.slice().sort((a, b) { 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原始数组保持不变。多条件按序生效比较函数按criteria数组的顺序逐条比较某条件比较结果非 0 立即返回为 0并列才进入下一个条件全部条件都并列时返回 0交由原生sort的稳定性保证原始相对顺序。键与函数统一处理typeof criterion function时视为选择器执行否则视为对象键a[criterion]直接取值。底层的比较语义compareValues单条件的比较结果由 src/_internal/compareValues.ts 计算。compareValues(a, b, order)在升序时做compareAscending(a, b)降序时交换操作数实现反转。值得注意的细节是它对null / undefined 的专门处理普通值排在最前rank 0null其次rank 1undefined最后rank 2同类空值之间视为相等返回 0保持原有相对顺序两个普通值按 JavaScript 原生/关系比较。这意味着即使排序字段存在缺失值sortBy也不会抛错而是把空值稳定地排到末尾。虽然 fp 版公开 API 只提供升序但底层复用同一个比较器因此该空值语义对 fp 版同样成立。四、更复杂的组合选择器函数与管道编排键可以混合选择器函数使用适合按计算值排序的场景。例如按分类优先、再按价格从高到低import { pipe, sortBy } from es-toolkit/fp; const products [ { name: laptop, price: 1000, category: electronics }, { name: shirt, price: 50, category: clothing }, { name: phone, price: 800, category: electronics }, ]; pipe( products, sortBy([ category, item -item.price, // 取负实现降序因为 sortBy 本身只升序 ]) );借助pipe可以把它嵌入更大的数据处理流。需要注意fp 版的pipe对连续的惰性函数map、filter、take等会做融合与短路优化见 pipe 文档而sortBy属于需要完整数组的急切eager操作因此排序通常放在管道中靠后的位置例如先过滤、再排序、最后截取import { filter, pipe, sortBy, take } from es-toolkit/fp; pipe( users, filter(user user.age 18), sortBy([age]), take(3) // 取年龄最小的前 3 位成年用户 );五、测试验证稳定性与不可变性fp 版sortBy的行为由 src/fp/array/sortBy.spec.ts 覆盖验证测试直接通过pipe(users, sortBy(...))断言结果测试用例断言内容单键排序sortBy([age])得到按 age 升序的完整数组多键排序sortBy([user, age])先按 user 再按 age 打破平局选择器函数sortBy([(item) item.age])与按键排序结果一致不可变性传入数组副本执行排序后原数组内容保持不变测试用例与文档示例保持一致读者可以把这些用例当作可运行的最小示例来理解 API 语义。六、总结与选型建议fp 版sortBy(criteria)data-last、可组合适合在pipe管道中使用返回的是待数据函数普通版sortBy(arr, criteria)data-first、一次调用即得结果适合在普通命令式代码中直接使用排序语义升序、稳定、多条件依次破平、不修改输入、空值排后底层链路fp 包装 → 普通 sortBy → orderBy 多条件比较 → compareValues 值比较。需要降序排序时官方建议直接使用支持desc方向的 orderBy它接收orders参数或在选择器函数中对值取负、取倒数等技巧在升序框架内实现反向效果。【免费下载链接】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),仅供参考