Lodash源码阅读-baseWhile

Lodash 源码阅读-baseWhile

概述

baseWhile 是 Lodash 内部的一个工具函数,它是实现 _.takeWhile_.dropWhile_.takeRightWhile_.dropRightWhile 等方法的基础。这个函数负责根据指定条件从数组中提取或排除元素,支持从数组开头或结尾开始处理。

前置学习

依赖函数

  • baseSlice:数组切片的底层实现函数
  • getIteratee:获取迭代器函数的工具

技术知识

  • 数组操作:理解数组索引和切片操作
  • 谓词函数:接受值并返回布尔值的函数
  • 循环控制:使用条件控制循环的执行方式
  • 高阶函数:接受或返回函数的函数设计模式
  • 函数组合:将多个函数组合在一起形成新功能

源码实现

javascript 复制代码
function baseWhile(array, predicate, isDrop, fromRight) {
  var length = array.length,
    index = fromRight ? length : -1;

  while (
    (fromRight ? index-- : ++index < length) &&
    predicate(array[index], index, array)
  ) {}

  return isDrop
    ? baseSlice(array, fromRight ? 0 : index, fromRight ? index + 1 : length)
    : baseSlice(array, fromRight ? index + 1 : 0, fromRight ? length : index);
}

实现思路

baseWhile 函数的实现思路巧妙而高效,它通过四个核心步骤完成工作:

  1. 初始化必要的变量,包括数组长度和起始索引位置
  2. 根据 fromRight 参数决定从数组的开头还是末尾开始循环
  3. 使用 while 循环,对数组元素应用谓词函数,直到找到第一个不满足条件的元素
  4. 根据 isDropfromRight 参数,选择适当的数组切片方式返回结果

这种实现允许一个函数同时支持四种不同的操作模式(take、drop、从左、从右),大大减少了代码重复。

源码解析

参数初始化

javascript 复制代码
var length = array.length,
  index = fromRight ? length : -1;

这里初始化了两个关键变量:

  • length:数组的长度,用于控制循环边界
  • index:迭代的起始位置,根据 fromRight 决定是从数组末尾(length)开始,还是从开头前一个位置(-1)开始

循环处理

javascript 复制代码
while (
  (fromRight ? index-- : ++index < length) &&
  predicate(array[index], index, array)
) {}

这个循环包含两个关键部分:

  1. 索引更新与边界检查:(fromRight ? index-- : ++index < length)

    • 从右侧开始:递减 indexindex--
    • 从左侧开始:递增 index 并检查是否小于数组长度(++index < length
  2. 条件检查:predicate(array[index], index, array)

    • 对当前元素应用谓词函数
    • 传入三个参数:当前元素值、索引和原数组
    • 只要谓词返回真值,循环就会继续

这个循环会一直运行,直到遇到第一个不满足谓词条件的元素,或者遍历完整个数组。

结果处理

javascript 复制代码
return isDrop
  ? baseSlice(array, fromRight ? 0 : index, fromRight ? index + 1 : length)
  : baseSlice(array, fromRight ? index + 1 : 0, fromRight ? length : index);

这部分代码根据 isDropfromRight 参数,调用 baseSlice 从数组中返回适当的切片:

  1. isDroptrue 时(丢弃模式):

    • 从右侧开始:保留索引 0 到 index 的元素
    • 从左侧开始:保留索引 index 到末尾的元素
  2. isDropfalse 时(保留模式):

    • 从右侧开始:保留索引 index+1 到末尾的元素
    • 从左侧开始:保留索引 0 到 index 的元素

这种设计让 baseWhile 能够灵活地处理四种不同的操作模式。

isDrop 参数不同取值的运行过程

我们通过具体例子来说明 isDrop 参数如何影响函数行为:

假设有数组 [1, 2, 3, 4, 5],谓词函数为 x => x < 3(即检查元素是否小于 3):

1. isDrop = false(保留满足条件的元素)

这对应于 takeWhiletakeRightWhile 函数:

  • 从左开始 (fromRight = false)

    • 循环从索引 0 开始,依次检查元素[1, 2],直到遇到元素 3(不满足条件)
    • 此时 index = 2
    • 返回 baseSlice(array, 0, 2)[1, 2]
    • 这就是 takeWhile 的行为:保留开头连续满足条件的元素
  • 从右开始 (fromRight = true)

    • 循环从末尾(索引 4)开始,因为没有元素满足条件(都大于等于 3)
    • 此时 index = 4(循环未进入)
    • 返回 baseSlice(array, 5, 5)[]
    • 如果数组是 [6, 5, 4, 2, 1],则会返回 [2, 1]
    • 这就是 takeRightWhile 的行为:保留末尾连续满足条件的元素
2. isDrop = true(丢弃满足条件的元素)

这对应于 dropWhiledropRightWhile 函数:

  • 从左开始 (fromRight = false)

    • 循环从索引 0 开始,依次检查元素[1, 2],直到遇到元素 3(不满足条件)
    • 此时 index = 2
    • 返回 baseSlice(array, 2, 5)[3, 4, 5]
    • 这就是 dropWhile 的行为:丢弃开头连续满足条件的元素
  • 从右开始 (fromRight = true)

    • 循环从末尾(索引 4)开始,因为没有元素满足条件(都大于等于 3)
    • 此时 index = 4(循环未进入)
    • 返回 baseSlice(array, 0, 5)[1, 2, 3, 4, 5](原数组)
    • 如果数组是 [6, 5, 4, 2, 1],则会返回 [6, 5, 4]
    • 这就是 dropRightWhile 的行为:丢弃末尾连续满足条件的元素

这种设计通过组合 isDropfromRight 参数,使得一个函数可以实现四种相关但不同的操作,展示了 Lodash 优秀的代码复用能力。注意循环的终止条件和切片范围的选择是这个函数的精髓所在。

总结

baseWhile 函数展示了 Lodash 优秀的代码设计原则:

  1. 代码复用:一个函数通过参数组合支持多种功能,减少重复代码
  2. 抽象分层:将核心逻辑抽象到内部函数,公共 API 只需简单包装
  3. 参数灵活性:通过布尔参数控制函数行为,实现多态
  4. 高效实现:通过精心设计的循环和条件判断,确保性能最优
相关推荐
小兔崽子去哪了5 分钟前
微信小程序入门
前端·vue.js·微信小程序
独立开阀者_FwtCoder8 分钟前
# 白嫖千刀亲测可行——200刀拿下 Cursor、V0、Bolt和Perplexity 等等 1 年会员
前端·javascript·面试
不和乔治玩的佩奇15 分钟前
【 React 】useState (温故知新)
前端
那小孩儿15 分钟前
?? 、 || 、&&=、||=、??=这些运算符你用对了吗?
前端·javascript
七月十二18 分钟前
[微信小程序]对接sse接口
前端·微信小程序
小七_雪球20 分钟前
Permission denied"如何解决?详解GitHub SSH密钥认证流程
前端·github
野原猫之助21 分钟前
tailwind css在antd组件中使用不生效
前端
菜鸟码农_Shi23 分钟前
Node.js 如何实现 GitHub 登录(OAuth 2.0)
javascript·node.js
没资格抱怨28 分钟前
如何在vue3项目中使用 AbortController取消axios请求
前端·javascript·vue.js
掘金酱32 分钟前
😊 酱酱宝的推荐:做任务赢积分“拿”华为MatePad Air、雷蛇机械键盘、 热门APP会员卡...
前端·后端·trae