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;
    }

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

相关推荐
Pop–6 分钟前
Vue3 el-tree:全选时只返回父节点,半选只返回勾选中的节点(省-市区-县-镇-乡-村-街道)
开发语言·javascript·vue.js
滿8 分钟前
Vue3 + Element Plus 动态表单实现
javascript·vue.js·elementui
钢铁男儿14 分钟前
C# 方法(值参数和引用参数)
java·前端·c#
阿金要当大魔王~~15 分钟前
面试问题(连载。。。。)
前端·javascript·vue.js
yuanyxh23 分钟前
commonmark.js 源码阅读(一) - Block Parser
开发语言·前端·javascript
进取星辰42 分钟前
22、城堡防御工事——React 19 错误边界与监控
开发语言·前端·javascript
ドロロ8062 小时前
element-plus点击重置表单,却没有进行重置操作
javascript·vue.js·elementui
海盐泡泡龟2 小时前
ES6新增Set、Map两种数据结构、WeakMap、WeakSet举例说明详细。(含DeepSeek讲解)
前端·数据结构·es6
t_hj3 小时前
Ajax案例
前端·javascript·ajax
bigHead-3 小时前
9. 从《蜀道难》学CSS基础:三种选择器的实战解析
前端·css