es-toolkit/fp 的 dropRight 使用指南:在 pipe 流水线中从数组末尾裁剪元素
【免费下载链接】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
导读
dropRight是 es-toolkit 函数式编程入口es-toolkit/fp提供的数组操作算子:调用dropRight(count)会返回一个新函数,该函数接收数组并移除其末尾的count个元素。与普通(data-first)的dropRight不同,fp 版采用>const result = pipe(array, dropRight(count));
官方文档特别提示了选用原则(见 docs/fp/reference/dropRight.md 与日文版 docs/ja/fp/reference/dropRight.md):
- 在普通代码(不组合流水线)中,建议直接使用 es-toolkit 原始的>import { dropRight, pipe } from 'es-toolkit/fp'; pipe([1, 2, 3, 4], dropRight(2)); // => [1, 2]
把
dropRight(2)单独取出来看,它就是一个等待数据的函数,这正是 fp 算子「配置与数据分离」的体现:const dropLastTwo = dropRight(2); // (array: readonly number[]) => number[] dropLastTwo([1, 2, 3, 4]); // => [1, 2] pipe([1, 2, 3, 4], dropLastTwo); // 与上面等价参数
count(number):需要从数组末尾移除的元素个数。
返回值
(array: readonly T[]) => T[]:一个将readonly T[]映射为「剩余元素数组」的函数。输入数组只读即可,输出是全新的数组,不会修改原数组。组合示例:与其它 fp 算子串联
dropRight的典型价值体现在流水线中——先截断、再变换,一气呵成:import { dropRight, map, pipe, take } from 'es-toolkit/fp'; const result = pipe( [1, 2, 3, 4, 5, 6], dropRight(2), // => [1, 2, 3, 4] map(x => x * 10), // => [10, 20, 30, 40] take(2) // => [10, 20] ); // => [10, 20]这段代码展示了 fp 入口的核心优势(详见 docs/fp/intro.md):每一步从上到下按执行顺序阅读,无需解析嵌套调用,也无需为中间结果创建临时变量。
源码实现解析:fp 封装与核心算法
fp 版
dropRight的实现非常简洁,它只是对普通版dropRight的柯里化封装。完整实现位于 src/fp/array/dropRight.ts:import { dropRight as dropRightToolkit } from '../../array/dropRight.ts'; export function dropRight<T>(count: number): (array: readonly T[]) => T[] { return function (array: readonly T[]): T[] { return dropRightToolkit(array, count); }; }可以看出:
dropRight(count)闭包捕获count,返回一个等待数组的新函数;- 真正的裁剪逻辑完全复用于普通版 src/array/dropRight.ts,fp 层不重复实现任何算法——这与 docs/fp/intro.md 中「
es-toolkit/fp复用es-toolkit的实现,只改变调用方式」的描述完全一致。
普通版
dropRight的核心算法如下(src/array/dropRight.ts):export function dropRight<T>(arr: readonly T[], itemsCount: number): T[] { itemsCount = Math.min(-itemsCount, 0); if (itemsCount === 0) { return arr.slice(); } return arr.slice(0, itemsCount); }这里有一个巧妙的小技巧:
Math.min(-itemsCount, 0)会对itemsCount取反并钳制到不大于 0,从而把「负数与 0 的输入」统一归一化为0(此时直接返回arr.slice()的副本),把「正数输入」转换为负的切片终点,最后通过arr.slice(0, itemsCount)一次性返回新数组。由于slice的终点是负数时会从数组末尾向前计算,dropRight([1, 2, 3, 4, 5], 2)实际等价于[1, 2, 3, 4, 5].slice(0, -2),得到[1, 2, 3]。该函数在 fp 数组模块的入口 src/fp/array/index.ts 中被导出,因此可以像
import { dropRight, pipe } from 'es-toolkit/fp'这样直接使用。边界情况与测试验证
普通版
dropRight的边界行为在 src/array/dropRight.spec.ts 中得到了系统性的测试覆盖,这些行为同样适用于 fp 版(fp 版直接委托给普通版实现):场景 输入 结果 说明 常规裁剪 dropRight([1.2, 2.3, 3.4], 1)[1.2, 2.3]移除末尾 1 个元素 移除 0 个 dropRight([1.2, 2.3, 3.4], 0)[1.2, 2.3, 3.4]返回完整数组 负数输入 dropRight([1.2, 2.3, 3.4], -1)[1.2, 2.3, 3.4]负数视为 0,不裁剪 小数输入 dropRight([1.2, 2.3, 3.4], 1.5)[1.2, 2.3]slice内部做整数化处理超出长度 dropRight([1.2, 2.3, 3.4], 4)[]移除数量不小于长度时返回空数组 原数组不变 — — 始终返回新数组,不改动输入 fp 版自身的冒烟测试位于 src/fp/array/dropRight.spec.ts,验证了其在 pipe 中的基本行为:
import { describe, expect, it } from 'vitest'; import { dropRight } from './dropRight.ts'; import { pipe } from '../pipe.ts'; describe('dropRight', () => { it('works in a pipe', () => { expect(pipe([1, 2, 3, 4], dropRight(2))).toEqual([1, 2]); }); });与 pipe 的关系:惰性求值视角
理解 fp 版
dropRight在pipe中的行为,还需要知道pipe的执行模型。从 src/fp/pipe.ts 的实现在看,pipe会把传入的函数按「是否支持惰性」分组:连续的惰性算子(如map、filter、take)会被融合成单次遍历;其余函数则逐个依次应用。dropRight本身没有标记lazy属性(从 src/fp/array/dropRight.ts 可以看到它只是一个普通函数,并未携带lazy元数据),因此它属于「急切(eager)」路径——在 pipe 中作为独立一步执行,返回完整的新数组后再交给下一步。这也符合它的语义:裁剪末尾元素必须知道整个数组的长度,天然无法像take那样提前短路。因此在使用时无需为性能担心:当pipe中同时存在map、filter、take等惰性算子时,它们之间仍会进行单遍融合优化(参见 src/fp/pipe.ts 的文档注释),dropRight只是作为普通步骤参与其中。总结
- fp 版
dropRight(count)返回一个 contenteditable="false">【免费下载链接】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),仅供参考