es-toolkit 函数式编程 zipWith:用 pipe 按索引合并多个数组的完整指南
2026/9/16 18:09:11 网站建设 项目流程

es-toolkit 函数式编程 zipWith:用 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

导读

es-toolkit/fpzipWith是一个数据优先(data-last)的高阶函数:它接收若干待合并的数组与一个combine函数,返回一个可接入pipe流水线的变换函数,将管道传入的数组与配置数组按索引一一结合。本文以 docs/ja/fp/reference/zipWith.md 为骨架,结合 fp 版实现源码、原始数组版实现 与单元测试,讲解它的用法、参数语义、长度不齐时的行为以及底层实现原理,读完即可在数据流水线中熟练使用zipWith完成多数组的按位合并。

核心概念:为 pipe 而生的数据优先 zipWith

函数式编程(fp)版的zipWith会创建一个函数,该函数将管道传入的数组与预先配置好的数组按索引合并。它专为与pipe组合使用而设计:

const result = pipe(array, zipWith(...arrs, combine));

在普通命令式代码中,优先使用 es-toolkit 原始版(非 fp)的zipWith;而当需要把zipWith作为变换步骤串联进pipe流水线时,才使用这里的fp版。这一分工与 es-toolkit/fp 的整体设计一致:pipees-toolkit/fp的入口(见 src/fp/index.ts 与 pipe.ts),每个 fp 函数都采用"先传配置、后收数据"的柯里化形态,由pipe依次供给数据。

使用示例

zipWith将管道传入的数组与配置数组在同一索引上的值一起交给combine。如果数组长度不同,缺失位置的值以undefined传入。

import { pipe, zipWith } from 'es-toolkit/fp'; // 两个等长数组按索引相加 pipe( [1, 2], zipWith([10, 20], (a, b) => a + b) ); // => [11, 22] // 长度不齐时,缺失值以 undefined 传入,可用默认参数兜底 pipe( [1, 2, 3], zipWith([10], (a, b = 0) => a + b) ); // => [11, 2, 3]

第二个例子中,[1, 2, 3]的长度为 3,而配置数组[10]的长度为 1,因此索引 1、2 处b的值为undefined,配合默认参数b = 0后计算结果分别为1123

参数

  • arrsArray<readonly unknown[]>):与管道传入数组一同合并的数组。
  • combine(...values: unknown[]) => R):接收各数组同一索引上的值(最后还附带索引),返回一个新值的函数。

返回值

返回(array: readonly T[]) => R[]:一个将管道传入数组映射为合并结果数组的函数。

源码原理:柯里化包装与参数重载

查看 fp 版实现 可以发现,它并没有重新实现合并逻辑,而是对原始版zipWith做了一层"延迟求值"包装:调用zipWith(...arrs, combine)时,先以rest收集全部配置参数并返回一个新函数;该函数被pipe调用时,再把管道传入的数组拼到配置参数前面,转调原始版完成合并:

export function zipWith(...rest: unknown[]): unknown { return function (array: readonly unknown[]): unknown[] { return (zipWithToolkit as (array: readonly unknown[], ...rest: unknown[]) => unknown[])(array, ...rest); }; }

这解释了文档中pipe(array, zipWith(...arrs, combine))的调用形态:zipWith的参数顺序(先数组、后 combine)与原始版完全一致,只是被柯里化成了"配置阶段 + 数据阶段"两步。

从类型重载可以看出,fp 版zipWith支持最多 1 个管道数组 + 3 个配置数组的组合(共 4 个数组),每个重载都会把index作为combine的最后一个参数传入(见 src/fp/array/zipWith.ts)。

底层合并逻辑与长度处理

fp 版转调的是 src/array/zipWith.ts 中的实现,其核心行为如下:

const arrs = [arr1, ...rest.slice(0, -1)]; const combine = rest[rest.length - 1] as (...items: any[]) => R; const maxIndex = Math.max(...arrs.map(arr => arr.length)); const result: R[] = Array(maxIndex); for (let i = 0; i < maxIndex; i++) { const elements: T[] = arrs.map(arr => arr[i]); result[i] = combine(...elements, i); }
  • 结果长度取最长数组maxIndex取所有数组长度的最大值,短数组缺失位置的值自然为undefined,这与文档描述完全一致;
  • 索引始终作为最后一个参数combine(...elements, i)保证combine的最后一个参数一定是当前索引i
  • 预分配结果数组Array(maxIndex)提前分配容量,避免动态扩容,从实现层面保证了性能。

与 pipe 的协作:普通函数的流水线语义

zipWith返回的是普通(非惰性)函数,pipe会将其与其他非惰性函数一样逐个顺序应用;只有连续出现mapfiltertake等惰性函数时,pipe才会融合为单趟短路求值(见 pipe.ts 的分组逻辑与 lazyPipe 的实现)。因此zipWith在流水线中遵循"上一步输出、下一步输入"的直觉语义,数据流自顶向下清晰可读。

测试验证:文档行为有据可依

src/fp/array/zipWith.spec.ts 用两个用例固化了文档描述的行为:

  1. 管道内正常工作pipe([1, 2], zipWith([10, 20], (a, b) => a + b))断言结果为[11, 22]
  2. 按最长数组取长度,缺失值传 undefinedpipe([1, 2, 3], zipWith(['a', 'b'], (a, b, index) => [a, b, index]))断言结果为[[1, 'a', 0], [2, 'b', 1], [3, undefined, 2]]

第二个用例同时验证了三点:结果长度等于最长数组长度(3)、缺失值以undefined传入、index作为combine的最后一个参数。这些断言与文档中"不同长度的数组,足りない値はundefinedとして渡される"(缺失值作为 undefined 传入)的说明相互印证。

实战建议与边界情况

  • 在 pipe 内使用 fp 版,在普通代码中使用原始版:若没有流水线需求,直接import { zipWith } from 'es-toolkit/array'调用原始版(参考 docs/reference/array/zipWith.md),API 更直接;
  • 处理长度不齐的数据:利用undefined补位特性,在combine中通过默认参数(如(a, b = 0) => a + b)或空值合并(a ?? 0)提供兜底逻辑,避免产生NaN或拼接出"undefined"
  • 利用索引参数combine的最后一个参数是索引,可用于生成带位置信息的合并结果,或实现需要"按位置加权"的业务逻辑;
  • 组合多个配置数组:fp 版重载支持同时传入 1~3 个配置数组,例如合并时间、价格、数量三组数据时,combine一次即可拿到全部按位对齐的值。

总结

es-toolkit 的 fp 版zipWith通过柯里化包装,将原始数组版zipWith无缝接入pipe数据流水线:它以"最长数组"为准进行按索引合并,缺失值以undefined补位,并把索引作为combine的最后一个参数。借助 fp 版源码、原始版源码 与单元测试 的相互印证,你可以放心地将它用于多数组对齐、按位求和、字符串拼接等流水线场景。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询