ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

es-toolkit/compat 中的 indexOf:支持 NaN 查找的 Lodash 兼容数组索引函数

es-toolkit/compat 中的 indexOf:支持 NaN 查找的 Lodash 兼容数组索引函数 es-toolkit/compat 中的 indexOf支持 NaN 查找的 Lodash 兼容数组索引函数【免费下载链接】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-toolkitindexOf是 es-toolkit 兼容层es-toolkit/compat中与 Lodash 行为 1:1 对齐的数组查找函数用于返回指定元素在数组中首次出现的索引。与原生Array.prototype.indexOf相比它的关键差异在于能够正确找到NaN值同时完整兼容fromIndex的正负偏移、整数强制转换以及类数组ArrayLike输入等 Lodash 语义。阅读本文后你将掌握indexOf的完整调用方式、边界行为以及其底层实现与测试覆盖从而在从 Lodash 迁移时无痛替换调用点。快速开始导入与基本用法在介绍细节之前先看最基本的调用方式。indexOf从es-toolkit/compat中导出其 TypeScript 签名如下const index indexOf(array, searchElement, fromIndex);函数签名对应三个参数待搜索的数组、要查找的值以及可选的起始搜索索引。与 Lodash 完全一致可以在不修改调用点的情况下直接替换lodash或lodash-es的导入路径详见 compat 迁移指南。在普通数组上查找元素的首次出现位置import { indexOf } from es-toolkit/compat; // 在数字数组中查找元素 const array [1, 2, 3, 4]; indexOf(array, 3); // 2 // 查找 NaN 值Array.prototype.indexOf 无法找到 const arrayWithNaN [1, 2, NaN, 4]; indexOf(arrayWithNaN, NaN); // 2为什么需要支持 NaN与原生 indexOf 的核心差异Array.prototype.indexOf基于严格相等比较元素而NaN NaN的结果是false因此原生方法永远无法通过indexOf找到NaN。Lodash 的indexOf弥补了这一缺陷es-toolkit/compat也保持了同样的行为。在 indexOf 的实现 中源码用一条Number.isNaN(searchElement)分支单独处理了这一场景// Array.prototype.indexOf doesnt find NaN values, so we need to handle that case separately. if (Number.isNaN(searchElement)) { fromIndex toInteger(fromIndex ?? 0); if (fromIndex 0) { fromIndex Math.max(0, array.length fromIndex); } for (let i fromIndex; i array.length; i) { if (Number.isNaN(array[i])) { return i; } } return -1; }当目标元素是NaN时实现不会走原生方法而是将fromIndex归一化负数转为相对数组末尾的正偏移且下限为 0然后线性遍历数组用Number.isNaN逐个匹配元素。Number.isNaN不会像全局isNaN那样对非数字类型做隐式转换因此不会产生误判。这一点在 indexOf 的测试用例 中有充分验证it(should work with a NaN searchElement, () { expect(indexOf([1, 2, 3, 4], NaN)).toBe(-1); expect(indexOf([1, NaN, 3, NaN], NaN)).toBe(1); expect(indexOf([1, NaN, 3, NaN], 3, 1)).toBe(2); expect(indexOf([1, NaN, 3, NaN], 3, -2)).toBe(2); expect(indexOf([1, NaN, 3, NaN], NaN, -32)).toBe(1); });当数组中确实存在NaN时返回其位置不存在时返回-1并且与fromIndex组合使用时行为正确。性能提示什么场景下应改用原生方法::: warning 建议优先使用Array.prototype.indexOf或Array.prototype.findIndex本indexOf函数因额外处理NaN的逻辑而运行较慢。如果你不是在查找NaN请使用更快的Array.prototype.indexOf要查找NaN请使用Array.prototype.findIndex配合Number.isNaN。:::这是官方文档开篇就给出的重要提示es-toolkit/compat中的indexOf为了完整复刻 Lodash 的NaN查找、类数组转换、假值fromIndex归一化等语义引入了额外的逻辑开销。如果你的业务数据中不存在NaN直接使用原生方法即可获得更好的性能而需要定位NaN时Array.prototype.findIndex配合Number.isNaN是更轻量的原生替代方案。从源码结构看这种取舍与 compat 层设计原则 一致兼容层为了 1:1 匹配 Lodash 行为会携带额外逻辑因此比严格 APIes-toolkit主包略大、略慢。追求极致性能的长期方案是在迁移完成后切换到严格 API。从指定位置开始搜索fromIndex 的完整语义indexOf支持从指定索引开始搜索。第三个参数fromIndex是可选的number默认值为0import { indexOf } from es-toolkit/compat; const array [1, 2, 3, 1, 2, 3]; indexOf(array, 2, 2); // 4 (start searching from index 2)上例中数组[1, 2, 3, 1, 2, 3]中数字2原本出现在索引 1但从索引 2 开始搜索后找到的是索引 4 处的第二个2。fromIndex的边界语义如下正数从该索引开始向后搜索若fromIndex array.length直接返回-1。负数从数组末尾反向计算起始位置即array.length fromIndex若计算结果小于 0则从索引 0 开始。小数会被强制转换为整数向下取整例如1.5视为1。假值falsey0、空字符串、null、undefined、NaN等一律按0处理。这些行为在源码和测试中都有依据。对于非NaN的搜索实现直接委托给Array.from(array).indexOf(searchElement, fromIndex)并在注释中说明原生方法已经处理了fromIndex -array.length、fromIndex array.length及整数转换等场景实现源码// Array.prototype.indexOf already handles fromIndex -array.length, fromIndex array.length // and converts fromIndex to an integer, so we dont need to handle those cases here. return Array.from(array).indexOf(searchElement, fromIndex);而对于NaN分支fromIndex则通过 toInteger 归一化——该函数先把值转换为有限数字toFinite再去除小数部分toFinite会把Infinity截断为Number.MAX_VALUE、把非数值转为0见 toFinite 实现。对应的测试覆盖如下测试用例it(should work with a negative fromIndex, () { expect(indexOf(array, 2, -3)).toBe(4); }); it(should work with a fromIndex length, () { const values [6, 8, 2 ** 32, Infinity]; const expected values.map(() [-1, -1, -1]); // 所有越界 fromIndex 均返回 -1 }); it(should convert fromIndex to an integer when searching for NaN, () { expect(indexOf([1, NaN, 2], NaN, 1.5)).toBe(1); expect(indexOf([1, NaN, 2], NaN, 2.9)).toBe(-1); }); it(should treat falsey fromIndex values as 0, () { const expected falsey.map(stubZero); // 假值 fromIndex 一律视作 0 });空值与类数组输入null、undefined 与 ArrayLikeindexOf对输入参数做了宽容处理null或undefined会被当作空数组查找结果恒为-1import { indexOf } from es-toolkit/compat; indexOf(null, 1); // -1 indexOf(undefined, 1); // -1这一行为由源码开头的一行守卫实现实现源码if (!isArrayLike(array)) { return -1; }::: infoarray可以是ArrayLikeT、null或undefined为确保与 Lodash 完全兼容indexOf函数按以下方式处理array如果array是ArrayLikeT则使用Array.from(...)将其转换为数组如果array是null或undefined则视为空数组。:::这意味着除了真正的数组indexOf还支持字符串、arguments对象以及任何带length属性的对象。其判断依据是 isArrayLike值不为null/undefined、不是函数且length属性符合有效长度非负且小于Number.MAX_SAFE_INTEGER的整数。在 测试用例 中类数组场景得到验证it(should support array-like, () { expect(indexOf({ 0: 1, 1: 2, length: 2 }, 2)).toBe(1); expect(indexOf(123, 2)).toBe(1); expect(indexOf(args, 2)).toBe(1); });需要注意的是正因为array声明为ArrayLikeT | null | undefined调用时传普通对象、数字等非类数组值时也会安全返回-1不会抛出异常测试用例it(should return -1 when provided none array-like object, () { expect(indexOf(1 as any, 1)).toBe(-1); });参数与返回值速查参数类型必填说明arrayT[]/ArrayLikeT/null/undefined是要搜索的数组。类数组会经Array.from转换null/undefined视为空数组searchElementT是要查找的值支持NaNfromIndexnumber否起始搜索索引默认0。负数从末尾反向计算小数与假值会被归一化返回值number返回数组中与给定值匹配的第一个元素的索引未找到匹配元素时返回-1。查找使用严格相等比较元素这与 Lodash 行为一致实现源码。总结何时使用 indexOf综合来看es-toolkit/compat的indexOf在以下场景最值得使用从 Lodash 迁移过程中保持调用点不变直接替换导入路径即可获得相同行为这是 compat 层的核心设计目标。需要查找NaN的位置这是它相对原生Array.prototype.indexOf的核心增值能力。输入可能是字符串、arguments 等类数组内置的ArrayLike支持免去了手动转换。反之如果确定数据中不存在NaN且追求极致性能官方文档明确建议优先使用原生Array.prototype.indexOf或findIndex Number.isNaN。从实现与测试实现、测试可以看出indexOf在正确性上严格对齐 Lodash性能上的额外开销则是兼容性语义的必然代价。【免费下载链接】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),仅供参考
返回列表