Lodash源码阅读-lastIndexOf

Lodash 源码阅读-lastIndexOf

概述

lastIndexOf 是 Lodash 中用于在数组中查找元素的方法,它返回找到的最后一个匹配元素的索引,如果没找到则返回 -1。与 JavaScript 原生的 Array.prototype.lastIndexOf 类似,但提供了更好的兼容性和对 NaN 值的特殊处理。

前置学习

依赖函数

  • strictLastIndexOf:Lodash 的内部从右向左查找函数
  • baseFindIndex:Lodash 的基础查找函数
  • baseIsNaN:Lodash 判断 NaN 的内部函数
  • toInteger:Lodash 的整数转换函数

技术知识

  • JavaScript 数组操作
  • NaN 值的特性(NaN !== NaN)
  • 数组索引的正负值处理
  • 类型转换

源码实现

js 复制代码
function lastIndexOf(array, value, fromIndex) {
  var length = array == null ? 0 : array.length;
  if (!length) {
    return -1;
  }
  var index = length;
  if (fromIndex !== undefined) {
    index = toInteger(fromIndex);
    index =
      index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
  }
  return value === value
    ? strictLastIndexOf(array, value, index)
    : baseFindIndex(array, baseIsNaN, index, true);
}

实现思路

lastIndexOf 函数的实现主要分为三个步骤:

  1. 首先处理边界情况,确保数组有效
  2. 然后处理起始位置参数,确保索引在有效范围内
  3. 最后根据查找值的类型(是否为 NaN)选择不同的查找策略

源码解析

1. 边界处理

js 复制代码
var length = array == null ? 0 : array.length;
if (!length) {
  return -1;
}
  • 使用 array == null 同时检查 nullundefined
  • 如果数组为空或无效,直接返回 -1

2. 索引处理

js 复制代码
var index = length;
if (fromIndex !== undefined) {
  index = toInteger(fromIndex);
  index =
    index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
}
  • 默认从数组末尾开始查找
  • 使用 toInteger 确保索引为整数
  • 处理负数索引:从数组末尾开始计算,且不小于 0
  • 处理正数索引:确保不超过数组最大索引

3. 查找策略

js 复制代码
return value === value
  ? strictLastIndexOf(array, value, index)
  : baseFindIndex(array, baseIsNaN, index, true);
  • 利用 NaN !== NaN 的特性判断是否为 NaN
  • 普通值使用 strictLastIndexOf 查找
  • NaN 值使用 baseFindIndex 配合 baseIsNaN 查找

应用场景

  1. 查找数组中最后一个匹配元素的位置
js 复制代码
// 在用户操作历史中查找最后一次点击某个按钮的记录
const userActions = ["click", "scroll", "click", "hover", "click"];
const lastClickIndex = _.lastIndexOf(userActions, "click"); // => 4

// 在商品列表中查找最后一个库存为0的商品
const products = [
  { id: 1, stock: 0 },
  { id: 2, stock: 5 },
  { id: 3, stock: 0 },
];
const lastOutOfStockIndex = _.lastIndexOf(products, { id: 3, stock: 0 }); // => 2
  1. 处理包含 NaN 的数组
js 复制代码
const arr = [1, NaN, 3, NaN];
const lastNaNIndex = _.lastIndexOf(arr, NaN); // 找到最后一个 NaN 的位置
  1. 从指定位置向前查找
js 复制代码
// 在聊天记录中查找最近的特定消息
const messages = ["hello", "world", "hello", "world"];
const lastHelloBeforeIndex = _.lastIndexOf(messages, "hello", 2); // => 0

// 在文件路径中查找最后一个目录分隔符
const path = "src/components/App.vue";
const lastSlashIndex = _.lastIndexOf(path, "/", path.length - 1); // => 13

总结

实现特点

  1. 健壮的空值处理
  2. 灵活的索引计算
  3. 特殊的 NaN 值处理
  4. 模块化的设计思路

设计原则

  1. 单一职责原则:将查找逻辑分离到专门的函数中
  2. 防御性编程:对各种边界情况进行处理
  3. 代码复用:通过基础函数组合实现复杂功能
相关推荐
CharlesYu016 小时前
前端性能优化的第一性原理,是不断缩短“用户发起意图 → 获得可用结果”之间的时间
前端
平头哥技术团队6 小时前
Day 21 _ 页内锚点_给每段起个 id,目录写 href=_#id_,点一下页面就滚到那一段
前端·html·html5
子兮曰7 小时前
Bun v1.4.1 深度解析:从 Zig 到 Rust,一场 11 天、64 个 AI 代理的语言迁徙
前端·后端·bun
人民广场吃泡面8 小时前
什么是AI Agent?它又能给前端带来哪些效率提升?
前端·人工智能
中科三方8 小时前
两家域名注册商资质被ICANN终止:企业域名资产安全再受关注
前端·网络·安全·域名
bug总结8 小时前
uniapp vue3全局方法注册使用
前端·javascript·uni-app
华无丽言9 小时前
如何在宜搭中实现获取子表中的字段值赋值到父表中?
前端·javascript·低代码
IT_陈寒9 小时前
Vue的computed属性竟然坑了我一把
前端·人工智能·后端
威斯软科的老司机9 小时前
通俗讲解 CNN 图像识别、向量 Embedding、Softmax 概率计算这三块的简化原理
前端·人工智能·ui·数字孪生
2601_9623824310 小时前
剑指大前端全栈工程师(全2册)主要情节
javascript·实战案例·全栈工程师·剑指大前端·html5+css3