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. 高效实现:通过精心设计的循环和条件判断,确保性能最优
相关推荐
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端
爱敲代码的小鱼10 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax