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. 代码复用:通过基础函数组合实现复杂功能
相关推荐
GISer_Jing5 分钟前
[总结篇]个人网站
前端·javascript
ss.li6 分钟前
TripGenie:畅游济南旅行规划助手:个人工作纪实(二十二)
javascript·人工智能·python
疯狂的沙粒26 分钟前
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
前端·uni-app·html
小妖66630 分钟前
html 滚动条滚动过快会留下边框线
前端·html
heroboyluck44 分钟前
Svelte 核心语法详解:Vue/React 开发者如何快速上手?
前端·svelte
海的诗篇_1 小时前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
琹箐1 小时前
ant-design4.xx实现数字输入框; 某些输入法数字需要连续输入两次才显示
前端·javascript·anti-design-vue
程序员-小李1 小时前
VuePress完美整合Toast消息提示
前端·javascript·vue.js
Uyker2 小时前
从零开始制作小程序简单概述
前端·微信小程序·小程序
Dontla5 小时前
为什么React列表项需要key?(React key)(稳定的唯一标识key有助于React虚拟DOM优化重绘大型列表)
javascript·react.js·ecmascript