拓冰建站拓冰建站
首页 / 资讯中心 / 正文

es-toolkit 的 Lodash 兼容版 `flatten`:单层扁平化的行为细节与实现原理

es-toolkit 的 Lodash 兼容版flatten单层扁平化的行为细节与实现原理【免费下载链接】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 的 Lodash 兼容模块es-toolkit/compat中的flatten函数展开说明它与核心es-toolkit版本flatten的差异、完整的参数语义ArrayLike、Arguments、Symbol.isConcatSpreadable、null/undefined等并结合 src/compat/array/flatten.ts、src/compat/array/flattenDepth.ts 与 src/compat/array/flatten.spec.ts 的源码与测试讲透兼容版flatten为什么慢一点、在什么场景下值得使用以及如何平滑迁移到核心 API。先看结论为什么文档建议优先使用es-toolkit的flattenes-toolkit/compat是为了与 Lodash 接口、行为 1:1 对齐而存在的兼容层见 docs/compat/intro.md。官方文档在flatten的日语参考页即 docs/ja/compat/reference/array/flatten.md开头给出了明确警告请使用es-toolkit的flatten。compat 版本的flatten因为要处理null/undefined、ArrayLike类型等运行会更慢。也就是说核心版es-toolkit/array的flatten只接受真正的数组readonly T[]行为等价于 JavaScript 原生的Array#flat但更快兼容版es-toolkit/compat的flatten为对齐 Lodash额外支持Arguments对象、任意ArrayLike、Symbol.isConcatSpreadable以及null/undefined输入因此多了一层类型判断逻辑性能略低、包体略大。两者共享同一个思想把嵌套数组展开一层depth 1。兼容版flatten的实现只有一行本质上是把工作委托给了flattenDepth// src/compat/array/flatten.ts export function flattenT(array: ArrayLikeT | readonly T[] | null | undefined): T[] { return flattenDepth(array as ListOfRecursiveArraysOrValuesT | null | undefined, 1); }兼容版flatten的完整行为规范基本用法单层扁平化flatten只展开一层嵌套更深层的数组保持原样import { flatten } from es-toolkit/compat; // 基本的扁平化1 层 flatten([1, [2, [3, [4]], 5]]); // 结果: [1, 2, [3, [4]], 5][3, [4]]这一层只被解开一次内层的[4]不会被继续展开。支持Arguments对象与 Lodash 一致兼容版flatten可以把函数内部的arguments对象当作数组处理import { flatten } from es-toolkit/compat; function example() { return flatten(arguments); } example(1, [2, 3], [[4]]); // 结果: [1, 2, 3, [4]]支持带Symbol.isConcatSpreadable的对象JavaScript 的Array.prototype.concat会检查对象的Symbol.isConcatSpreadable属性来决定是否将其展开Lodash 的flatten也复用了这一约定兼容版同样支持import { flatten } from es-toolkit/compat; const spreadable { 0: a, 1: b, length: 2, [Symbol.isConcatSpreadable]: true }; flatten([1, spreadable, 3]); // 结果: [1, a, b, 3]null与undefined视为空数组这是 Lodash 兼容行为中最常见的一个差异点传入null或undefined不会抛错而是返回空数组。import { flatten } from es-toolkit/compat; flatten(null); // [] flatten(undefined); // [] flatten([]); // []参数与返回值arrayArrayLikeT | null | undefined需要扁平化的数组或类数组对象。返回值T[]扁平化后的新数组不会修改原数组。注意返回值类型是T[]由于只展平一层元素类型在类型层面不会像flattenDeep那样被递归推导。源码级原理flattenDepth与isFlattenable兼容版flatten内部委托给 src/compat/array/flattenDepth.ts其中depth 1。核心逻辑如下// src/compat/array/flattenDepth.ts节选 export function flattenDepthT(array: ListOfRecursiveArraysOrValuesT | null | undefined, depth 1): T[] { if (!isArrayLike(array)) { return []; } const result: T[] []; const flooredDepth Math.floor(depth); const recursive (arr: readonly T[], currentDepth: number) { for (let i 0; i arr.length; i) { const item arr[i]; if (isFlattenable(item) currentDepth flooredDepth) { recursive(item as T[], currentDepth 1); } else { result.push(item); } } }; recursive(Array.from(array) as T[], 0); return result; } function isFlattenable(value: unknown): boolean { return isArray(value) || isArguments(value) || Boolean(value (value as any)[Symbol.isConcatSpreadable]); }由此可以归纳出兼容版flatten的几个关键实现事实入口先做isArrayLike检查非类数组对象如{ 0: a }直接返回[]。这是flatten(null)、flatten(undefined)返回[]的根源。可扁平化判定有三条isArray真数组、isArgumentsarguments对象、或对象上存在真值的Symbol.isConcatSpreadable属性。这也解释了文档示例中spreadable对象能被展开的原因。深度受Math.floor控制depth会被向下取整flatten传1即只递归一层。稀疏数组会被压实测试 src/compat/array/flatten.spec.ts 验证了flatten([[1, 2, 3], Array(3)])的结果是[1, 2, 3, undefined, undefined, undefined]即空洞位置会被补成undefined这也是 Lodash 行为之一。isArrayLikeObject的逐项拷贝逻辑还可参考 src/compat/_internal/flattenArrayLike.ts它展示了类数组元素如何被逐个push进结果数组。与核心版flatten的对比核心 API 的实现在 src/array/flatten.ts两者差异集中体现在接受什么输入、怎么判定嵌套元素上维度核心版es-toolkit/array兼容版es-toolkit/compat签名flattenT, D(arr: readonly T[], depth 1)flattenT(array: ArrayLikeT \| readonly T[] \| null \| undefined)嵌套元素判定仅Array.isArray(item)isArray/isArguments/Symbol.isConcatSpreadable三者其一是否接受null/undefined不接受类型上不合法接受返回[]是否接受类数组 /arguments不接受接受深度参数支持泛型D会反映到返回类型ArrayFlatArrayT[], D固定为 1flatten层面类型为T[]性能判定路径最短更快多类型判断略慢、包体略大因此文档的建议非常明确如果你的代码不依赖 Lodash 的null/undefined、arguments、类数组等兼容语义直接用核心版import { flatten } from es-toolkit/array; flatten([1, [2, 3], [4, [5, 6]]]); // [1, 2, 3, 4, [5, 6]] flatten([1, [2, 3], [4, [5, 6]]], 2); // [1, 2, 3, 4, 5, 6]核心版的行为与原生Array#flat一致但由于内部用显式循环而非concat展开实际运行更快。迁移路径从兼容版到核心版按照 docs/compat/intro.md 推荐的迁移流程第一步把lodash/lodash-es的导入直接换成es-toolkit/compat调用点一行不改行为保持一致import { flatten } from es-toolkit/compat;第二步逐步清理调用点确认代码中没有依赖arguments、类数组、null/undefined等 Lodash 特殊语义后改用核心 APIimport { flatten } from es-toolkit/array;换来的是更小的打包体积和更快的运行速度。如果你确实需要展平任意深度的兼容行为兼容层还提供flattenDeep与flattenDepth见 src/compat/array/flattenDeep.ts内部以Infinity为深度调用flattenDepth可按需选用。测试佐证行为由测试用例锁定src/compat/array/flatten.spec.ts 用 Vitest 覆盖了以下行为可作为兼容性契约的参考扁平化arguments对象flatten([args, [args]])得到[1, 2, 3, args]稀疏数组按稠密数组处理空洞补undefined带真值Symbol.isConcatSpreadable的对象被展开空数组嵌套[[], [[]], [[], [[[]]]]]只展平一层多层嵌套数组只展平一层非类数组对象{ 0: a }返回[]类数组支持flatten({ 0: [1, 2, 3], length: 1 })、flatten(123)、flatten(args)均按预期展开。这些测试同时兼容 Lodash 自身的测试套件是es-toolkit/compat实现 100% 兼容目标的直接证据。小结兼容版flatten以1 层深度展开嵌套数组完整支持Arguments、Symbol.isConcatSpreadable、类数组对象并将null/undefined视为空数组它内部委托给flattenDepth通过isFlattenableisArray/isArguments/isConcatSpreadable三选一判定可展开元素这些额外语义带来了可感知的性能与包体开销因此官方文档明确建议新代码优先使用es-toolkit/array的核心版flatten只有迁移 Lodash 存量代码、且依赖其特殊行为时才使用es-toolkit/compat版本并在迁移完成后逐步切换回核心 API。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门