es-toolkit 的 lodash 兼容 transform:数组与对象的通用累积器(Accumulator)详解

es-toolkit 的 lodash 兼容 transform:数组与对象的通用累积器(Accumulator)详解 es-toolkit 的 lodash 兼容 transform数组与对象的通用累积器Accumulator详解【免费下载链接】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-toolkittransform是 es-toolkit 兼容层es-toolkit/compat中与 lodash 同名 API 对齐的工具函数用于遍历数组或对象并在一个累积器accumulator上逐步累积结果最终产出新的值。本文基于 transform 参考文档 展开并结合源码与测试说明其完整用法、参数语义、提前终止机制以及为什么官方建议大多数场景优先使用reduce或Object.entries。::: warning 注意官方建议优先使用reduce或Object.entries该函数内部逻辑复杂运行较慢。在大多数场景下使用 JavaScript 内置的reduce或Object.entries可以更简单地实现同样效果。:::函数签名与总体语义transform的典型调用形式如下const result transform(object, iteratee, accumulator);它遍历数组或对象将每个元素交给iteratee函数处理iteratee把中间结果累积到accumulator中当iteratee返回false时提前停止遍历最终返回累积后的结果。在 es-toolkit 的兼容层中transform从es-toolkit/compat导出并注册在兼容入口 compat.ts 中import { transform } from es-toolkit/compat;参数说明参数类型说明objectreadonly T[] \| T可选要遍历的数组或对象。iteratee(accumulator, value, key, object) unknown可选对每个元素执行的函数返回false时终止遍历。默认值为identity函数即原样返回输入。accumulatorU可选初始累积值。省略时遍历数组自动创建空数组遍历对象自动创建空对象。返回值U \| any[] \| Recordstring, any累积后的最终结果。基本用法遍历数组与对象transform最典型的用法是给定一个初始累积器遍历源数据并把每次迭代的结果写回累积器。遍历数组import { transform } from es-toolkit/compat; const numbers [2, 3, 4]; const doubled transform( numbers, (acc, value) { acc.push(value * 2); }, [] ); // Returns: [4, 6, 8]遍历对象遍历对象时iteratee的第二个参数是属性值第三个参数是属性键keyimport { transform } from es-toolkit/compat; const obj { a: 1, b: 2, c: 1 }; const grouped transform( obj, (result, value, key) { (result[value] || (result[value] [])).push(key); }, {} ); // Returns: { 1: [a, c], 2: [b] }上面的例子把原对象按值分组值相同的一组归入同一个数组键下直观展示了累积器的灵活形态——它可以是数组、普通对象也可以是任意自定义结构。省略 accumulator自动创建空数组或空对象如果不提供第三个参数accumulatortransform会依据object的类型自动创建初始累积器数组创建空数组对象创建空对象。import { transform } from es-toolkit/compat; // 数组自动创建空数组 const result1 transform([1, 2, 3], (acc, value) { acc.push(value * 2); }); // Returns: [2, 4, 6] // 对象自动创建空对象 const result2 transform({ a: 1, b: 2 }, (acc, value, key) { acc[key] value * 2; }); // Returns: { a: 2, b: 4 }这一自动创建逻辑可以在 transform.ts 的源码中找到依据当accumulator null时函数先判断object是否为数组、Buffer 或 TypedArrayArray.isArray(object) || isBuffer(object) || isTypedArray(object)若是则创建[]否则若对象有可用的构造函数则通过Object.create(Object.getPrototypeOf(object))创建与原对象相同原型的新对象其余情况退化为普通{}。值得注意的细节是对于类实例如new Foo()省略accumulator时创建的累积器会继承相同的[[Prototype]]这一点由测试 transform.spec.ts 验证——测试断言transform(new Foo(), iteratee)的结果instanceof Foo为true。此外测试还覆盖了两个边界TypedArray 会转换为普通数组transform对 TypedArray 自动创建的累积器是普通数组见 transform.spec.ts假值falsey输入返回空对象对null、undefined、false、0、等输入不提供累积器时得到空对象{}见 transform.spec.ts。提前终止iteratee 返回 falsetransform支持在遍历过程中提前退出只要iteratee返回严格等于false的值剩余元素就不再被处理。import { transform } from es-toolkit/compat; const numbers [1, 2, 3, 4, 5]; const result transform( numbers, (acc, value) { if (value 3) { return false; // Stop iteration } acc.push(value * 2); }, [] ); // Returns: [2, 4, 6] (4 and 5 are not processed)这一行为由底层的forEach实现支撑在 forEach.ts 中每次回调后都会检查result false并break跳出循环。测试 transform.spec.ts 分别验证了数组和对象场景下返回false只会处理第一个元素。省略 iteratee返回空数组或空对象如果只传第一个参数、省略iterateetransform默认使用identity函数原样返回每个值由于没有向累积器写入任何内容最终返回的是空数组或空对象import { transform } from es-toolkit/compat; const array [1, 2, 3]; const copy1 transform(array); // Returns: [] const obj { a: 1, b: 2 }; const copy2 transform(obj); // Returns: {}从源码 transform.ts 可见iteratee参数的默认值正是identity随后又经过createIteratee归一化处理identity本身定义于 identity.ts即x x。深入源码transform 的执行流程transform的核心实现位于 transform.ts整体流程可分为四步判定输入类型Array.isArray(object) || isBuffer(object) || isTypedArray(object)决定是否按数组语义处理归一化 iteratee通过 iteratee.ts 中的iteratee()工厂函数处理——函数原样返回字符串/数字转为属性读取器双元素数组转为matchesProperty普通对象转为matches匹配器创建或保留累积器accumulator为空时按上文规则自动创建遍历并累积委托给forEach(object, (value, key, object) iteratee(accumulator, value, key, object))最后返回累积器。关于iteratee收到的参数测试给出了精确约定见 transform.spec.ts对于数组参数依次为(新累积器, 元素值, 索引, 原数组)对于对象参数依次为(新累积器, 属性值, 属性键, 原对象)。注意第一个参数是自动创建的累积器其与原输入不是同一个引用但类型保持一致第三个参数在数组场景是索引、在对象场景是键。此外测试还验证了稀疏数组会被当作密集数组处理transform(Array(1), ...)会得到[undefined]见 transform.spec.ts这源于forEach使用Object.keys/range生成完整索引序列的遍历方式。何时使用、何时改用内置方法transform适合需要统一处理数组与对象、且累积器形态自由的场景尤其是按任意规则把集合折叠成自定义结构时。但正如文档开头警告所述其内部逻辑原型链判断、iteratee 归一化、类型分派带来额外开销性能敏感路径上不推荐使用。以下等价写法可以直接替换// 数组场景reduce 完全覆盖 const doubled [2, 3, 4].reducenumber[]((acc, value) { acc.push(value * 2); return acc; }, []); // 对象场景Object.entries 更直接 const obj { a: 1, b: 2, c: 1 }; const grouped Object.entries(obj).reduceRecordnumber, string[]((result, [key, value]) { (result[value] || []).push(key); return result; }, {});小结transform是 es-toolkit 兼容层对 lodash 同名 API 的忠实移植支持数组、对象、Buffer、TypedArray 等多种输入支持自动创建累积器、false提前终止、默认identityiteratee并尽量保持与 lodash 一致的原型继承与参数约定。需要与 lodash 行为严格对齐、且非性能瓶颈的存量代码可直接从es-toolkit/compat引入而新代码建议优先采用reduce与Object.entries等内置方案。相关实现与测试可进一步参阅 transform.ts 与 transform.spec.ts。【免费下载链接】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),仅供参考