Lodash源码阅读-baseFindIndex

Lodash 源码阅读-baseFindIndex

一、介绍

baseFindIndex 是 Lodash 中一个重要的内部工具函数,它的主要作用是在数组中查找满足特定条件的元素的索引。这个函数非常灵活,因为它接受一个判断函数(predicate)作为参数,可以根据不同的条件来查找元素。它是 Lodash 中很多数组方法的基础,比如 findIndexfindLastIndexindexOf(查找 NaN 值时)等。

二、源码实现

js 复制代码
function baseFindIndex(array, predicate, fromIndex, fromRight) {
  var length = array.length,
    index = fromIndex + (fromRight ? 1 : -1);

  while (fromRight ? index-- : ++index < length) {
    if (predicate(array[index], index, array)) {
      return index;
    }
  }
  return -1;
}

三、实现原理

1. 整体思路

说人话就是:这个函数就像是一个数组探索器,可以从左往右或者从右往左遍历数组,每到一个位置就问一下"这个是我要找的吗?"(通过 predicate 函数判断)。如果是,就说"找到了,在这个位置";如果找完了都没找到,就说"没找到,返回 -1"。

具体来说:

  1. 可以指定从哪个位置开始找(fromIndex)
  2. 可以指定是从左往右找还是从右往左找(fromRight)
  3. 可以自定义判断条件(predicate)
  4. 找到就返回位置,找不到返回 -1

2. 参数说明

  • array:要搜索的数组
  • predicate:判断函数,用来判断是否是要找的元素
  • fromIndex:从哪个位置开始找
  • fromRight:是否从右边开始找(true 表示从右往左,false 表示从左往右)

3. 逐行解析

js 复制代码
var length = array.length,
  index = fromIndex + (fromRight ? 1 : -1);
  • 先记住数组的长度
  • 设置初始索引位置:
    • 如果是从右往左找(fromRight 为 true),则初始索引为 fromIndex + 1
    • 如果是从左往右找(fromRight 为 false),则初始索引为 fromIndex - 1
  • 这样设置是因为在循环开始时会先执行 index-- 或 ++index
js 复制代码
while (fromRight ? index-- : ++index < length) {
  • 这是一个巧妙的循环条件,根据 fromRight 参数决定遍历方向:
    • 如果 fromRight 为 true,则条件是 index--,从右往左遍历
    • 如果 fromRight 为 false,则条件是 ++index < length,从左往右遍历
  • 使用前置递增/递减运算符确保在第一次比较前就更新索引
js 复制代码
if (predicate(array[index], index, array)) {
  return index;
}
  • 对每个元素调用 predicate 函数进行判断
  • predicate 函数接收三个参数:当前元素、索引和整个数组
  • 如果 predicate 返回真值,表示找到了匹配的元素,立即返回当前索引
js 复制代码
return -1;
  • 如果循环结束都没有找到匹配的元素,则返回 -1

四、使用示例

虽然 baseFindIndex 是内部函数,不直接暴露给用户,但我们可以通过 Lodash 的公共函数看到它的作用:

js 复制代码
// 1. 通过 _.findIndex 使用
_.findIndex([1, 2, 3, 4], function (n) {
  return n % 2 === 0;
}); // => 1 (找到第一个偶数的索引)

// 2. 通过 _.findLastIndex 使用
_.findLastIndex([1, 2, 3, 4], function (n) {
  return n % 2 === 0;
}); // => 3 (找到最后一个偶数的索引)

// 3. 通过 _.indexOf 查找 NaN 值时使用
_.indexOf([1, NaN, 3], NaN); // => 1 (内部使用 baseFindIndex 和 baseIsNaN)

// 4. 指定起始位置
_.findIndex(
  [1, 2, 3, 4, 5],
  function (n) {
    return n > 3;
  },
  3
); // => 3 (从索引3开始查找大于3的元素)

// 5. 从右向左查找
// 内部实现中,findLastIndex 会调用 baseFindIndex 并设置 fromRight 为 true
_.findLastIndex([1, 2, 3, 2, 1], function (n) {
  return n === 2;
}); // => 3 (从右往左找到的第一个值为2的元素索引)

五、总结

  1. 方向控制

    js 复制代码
    while (fromRight ? index-- : ++index < length)

    通过三元运算符巧妙地控制遍历方向,一个函数同时支持从左往右和从右往左查找

  2. 索引初始化

    js 复制代码
    index = fromIndex + (fromRight ? 1 : -1);

    根据遍历方向预先调整索引,确保循环开始时能正确处理第一个元素

  3. 参数传递

    js 复制代码
    predicate(array[index], index, array);

    传递完整的上下文信息给 predicate 函数,增强灵活性

  4. 早期返回

    js 复制代码
    if (predicate(array[index], index, array)) {
      return index;
    }

    找到匹配项立即返回,避免不必要的遍历

相关推荐
IT、木易20 分钟前
大白话阐述react和vue高阶组件的概念、优势及应用场景,以及区别,给出简单高阶组件的实现代码
前端·vue.js·react.js
HaanLen21 分钟前
React19源码系列之FiberRoot节点和Fiber节点
前端·javascript·react.js
冴羽32 分钟前
SvelteKit 最新中文文档教程(3)—— 数据加载
前端·javascript·svelte
百万蹄蹄向前冲1 小时前
组建百万前端梦之队-计算机大学生竞赛发展蓝图
前端·vue.js·掘金社区
云隙阳光i1 小时前
实现手机手势签字功能
前端·javascript·vue.js
imkaifan1 小时前
vue2升级Vue3--native、对inheritAttrs作用做以解释、声明的prop属性和未声明prop的属性
前端·vue.js·native修饰符·inheritattrs作用·声明的prop属性·未声明prop的属性
觉醒法师1 小时前
HarmonyOS NEXT - 电商App实例三( 网络请求axios)
前端·华为·typescript·axios·harmonyos·ark-ts
Danta2 小时前
HTTP协议版本演进:从HTTP/0.9到HTTP/3的高分面试回答
前端·网络协议·面试
柠檬树^-^2 小时前
app.config.globalProperties
前端·javascript·vue.js
太阳花ˉ2 小时前
react(一):特点-基本使用-JSX语法
前端·react.js