ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

es-toolkit 兼容版 differenceBy:基于迭代器转换的差集计算完全指南

2026/9/16 15:47:18 拓冰建站 浏览量
es-toolkit 兼容版 differenceBy:基于迭代器转换的差集计算完全指南 es-toolkit 兼容版 differenceBy基于迭代器转换的差集计算完全指南【免费下载链接】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-toolkitdifferenceBy是 es-toolkit 的 Lodash 兼容模块es-toolkit/compat中提供的高阶差集函数它先用迭代器iteratee把每个元素转换为比较基准值再从第一个数组中剔除在其他数组中转换后值相同的元素。本文以 docs/ja/compat/reference/array/differenceBy.md 为骨架结合仓库源码与测试用例讲解其完整用法、参数语义、实现原理与边界行为读完即可在迁移 Lodash 或做数据清洗时直接上手。一、函数定位与适用场景const result differenceBy(array, ...values, iteratee);differenceBy解决的核心问题是按转换后的值做差集直接比较原始值往往不符合业务语义例如2.1与2.3在按Math.floor转换后都是2应视为相同。此时用它就能以某个属性、字符串长度或任意映射结果为基准求差集非常适合对象数组按特定属性去重/求差如按id比较两个用户列表按派生值比较如按字符串长度、按取整后的数值比较需要 Lodash 行为兼容的存量项目函数签名、-0归一化、NaN匹配等细节与 Lodash 保持一致。需要特别注意的是文档开头给出了明确的性能提示兼容版differenceBy因复杂的参数处理和迭代器转换运行较慢建议优先使用 es-toolkit 原生的快速版 differenceBy源码位于 src/array/differenceBy.ts。兼容版的价值在于行为兼容、无缝迁移追求极致性能时则应切换到原生版本。二、安装与导入兼容版函数从es-toolkit/compat子路径导入import { differenceBy } from es-toolkit/compat;compat模块的完整入口定义在 src/compat/index.ts 与 src/compat/compat.ts其设计目标是与 Lodash 保持 API 与行为兼容便于项目无痛迁移。三、核心用法详解3.1 使用函数迭代器按转换结果比较最直接的形式是传入一个映射函数先转换再比较import { differenceBy } from es-toolkit/compat; // 小数点以下切り捨てで比較按向下取整结果比较 differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // Returns: [1.2] (Math.floor(2.1) Math.floor(2.3) ため2.1を除外) // 说明2.1 与 2.3 取整后同为 2因此 2.1 被剔除仅保留 1.2这里Math.floor同时作用于第一个数组的元素和所有待排除数组的元素转换后值相等的元素从结果中剔除。3.2 使用属性名迭代器按属性比较第二个参数可以传字符串属性名此时会提取每个元素的该属性值作为比较基准import { differenceBy } from es-toolkit/compat; // 按字符串长度比较 differenceBy([one, two, three], [four, eight], length); // Returns: [one, two] // 说明three 与 eight 长度都是 5因此 three 被剔除 // 按对象 id 属性比较 const users1 [ { id: 1, name: Alice }, { id: 2, name: Bob }, ]; const users2 [{ id: 1, name: Different Alice }]; differenceBy(users1, users2, id); // Returns: [{ id: 2, name: Bob }] // 说明id 为 1 的对象即使 name 不同被剔除属性名迭代器让按对象数组的某个字段求差集变得一行即可完成。3.3 一次排除多个数组...values支持任意数量的待排除数组且每个数组都会先经迭代器转换再参与比较import { differenceBy } from es-toolkit/compat; // 多个数组同时排除 differenceBy([2.1, 1.2, 3.5], [2.3], [1.4], [3.2], Math.floor); // Returns: [] (取整后 2、1、3 全部被覆盖所有元素均被剔除) // 字符串数组按长度比较 differenceBy([a, bb, ccc], [x], [yy], [zzz], length); // Returns: [] (长度 1、2、3 均被覆盖)从源码看待排除数组会被拍平合并后再统一转换比较见下文实现原理。3.4 不传迭代器退化为 difference当最后一个参数是数组而非函数、属性名等时differenceBy等价于普通差集import { differenceBy } from es-toolkit/compat; // 不传迭代器 differenceBy([1, 2, 3], [2, 4]); // Returns: [1, 3]这一点在测试 src/compat/array/differenceBy.spec.ts 中也有验证differenceBy([2, 1, 2, 3], [3, 4], [3, 2])返回[1]。3.5 空值与空数组处理null或undefined作为第一个数组时一律返回空数组import { differenceBy } from es-toolkit/compat; differenceBy(null, [1, 2], Math.floor); // Returns: [] differenceBy(undefined, [1, 2], x x); // Returns: []对应实现见 src/compat/array/differenceBy.ts入口处先通过isArrayLikeObject检查非类数组对象直接返回[]。测试 src/compat/array/differenceBy.spec.ts 进一步证明字符串23作为首个参数也会返回[]。四、参数与返回值规范项目类型说明arrayArrayLikeT \| null \| undefined求差集的基准数组可为类数组对象非类数组或空值返回[]...valuesArrayArrayLikeT待排除元素所在的一个或多个数组iterateeValueIterateeT将每个元素转换为比较值的迭代器支持函数、属性名、属性值对或部分对象返回值T[]剔除转换后值相同元素后的新数组不修改原数组其中ValueIterateeT的类型定义位于 src/compat/_internal/ValueIteratee.tsexport type ValueIterateeT ((value: T) unknown) | (PropertyKey | [PropertyKey, any] | PartialShallowT);即迭代器可以是函数、属性键PropertyKey即字符串/数字/symbol、[属性键, 期望值]二元组、或部分对象。五、迭代器转换机制源码级原理兼容版differenceBy会把最后一个参数当作迭代器交给统一的迭代器工厂createIteratee处理。工厂函数实现在 src/compat/util/iteratee.ts转换规则如下传入的迭代器转换结果说明null/undefinedidentity原样返回输入等价于不转换函数原函数直接使用如Math.floor二元数组[a, 1]matchesProperty(a, 1)判断元素属性a是否等于1对象matches(obj)判断元素是否匹配该部分对象其他属性键property(value)提取元素对应属性值如length、id这解释了为什么length、id这类字符串能直接作为迭代器使用也意味着兼容版支持 Lodash 风格的[a, 1]属性值对写法。配套的matchesProperty、matches、property实现分别位于 src/compat/predicate/matchesProperty.ts、src/compat/predicate/matches.ts、src/compat/object/property.ts。六、兼容版实现流程与边界行为6.1 主实现流程兼容版函数体位于 src/compat/array/differenceBy.ts执行步骤如下空值防护isArrayLikeObject(array)为假则直接返回[]提取迭代器last(_values)取最后一个参数作为迭代器拍平待排除数组flattenArrayLike(_values)将多个类数组参数拍平为单一数组实现见 src/compat/_internal/flattenArrayLike.ts跳过其中非类数组的值判断分支若迭代器本身是类数组对象说明没传迭代器调用原生 difference 求普通差集否则调用原生differenceBy并传入createIteratee(iteratee)转换后的迭代器结果归一化对每个结果元素执行normalizeZero把-0归一为0对齐 Lodash 行为见 src/compat/_internal/normalizeZero.ts。6.2 底层原生实现基于 Set 的 O(n) 算法无论走哪个分支最终都由 es-toolkit 原生实现完成核心计算。原生differenceBysrc/array/differenceBy.ts的算法非常简洁高效对第二个数组逐元素应用mapper构建Set利用 Set 的哈希查找遍历第一个数组对每个元素应用mapper若映射结果不在 Set 中则保留。const mappedSecondSet new Set(secondArr.map(item mapper(item))); return firstArr.filter(item { return !mappedSecondSet.has(mapper(item)); });由于Set.has是常数级查找整体时间复杂度为 O(n)这也是原生版性能优于兼容版兼容版额外承担了参数解析、数组拍平与迭代器转换开销的根本原因。原生differencesrc/array/difference.ts采用同样的 Set 策略。6.3 测试覆盖的边界行为src/compat/array/differenceBy.spec.ts 完整覆盖了以下 Lodash 兼容语义可作为行为契约参考-0归一化为0differenceBy([-0, 1], [1])返回[0]L48-L56并在显式传迭代器时同样生效L128-L130NaN匹配differenceBy([1, NaN, 3], [NaN, 5, NaN])返回[1, 3]说明NaN能被正确识别为相同值L58-L60大型数组以LARGE_ARRAY_SIZE规模验证性能与正确性L62-L74arguments与类数组对象{ 0: 1, 1: 2, length: 2 }这类类数组可直接作为基准或排除来源L104-L117非数组值过滤排除参数中的非类数组值如字符串2会被跳过不会破坏结果L123-L126。6.4 类型重载为了在 TypeScript 下精确推导返回类型兼容版对 1 到 6 个排除数组分别声明了重载T1~T6泛型第 7 个起落入剩余参数重载见 src/compat/array/differenceBy.ts。这意味着对T1[]与T2[]混合求差集时返回类型始终是第一个数组的元素类型T1[]。七、与原生 differenceBy 的选型建议维度es-toolkit/compat兼容版es-toolkit 原生版导入路径es-toolkit/compates-toolkit迭代器形式函数 / 属性名 / 属性值对 / 部分对象仅函数mapper多数组排除支持任意数量仅支持两个数组-0→0归一化支持对齐 Lodash不支持空值 / 非类数组参数安全返回[]由调用方自行保证性能较慢参数解析 迭代器转换开销更快纯 Set 算法结论正在从 Lodash 迁移、需要严格行为兼容的代码用es-toolkit/compat的differenceBy新代码追求性能与简洁直接用 es-toolkit 原生 differenceBy对应源码 src/array/differenceBy.ts。如需进一步了解兼容模块的整体设计可阅读 compat 模块说明。【免费下载链接】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),仅供参考