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. 高效实现:通过精心设计的循环和条件判断,确保性能最优
相关推荐
用户0595401744623 分钟前
LLM对话记忆测试踩坑实录:手工回归30分钟,自动化后2分钟发现3个隐藏Bug
前端·css
Ashley的成长之路2 小时前
前端性能优化实战手册·第2篇:资源加载策略全解
前端·性能优化·资源加载·http/3·性能优化实战·资源加载优化
浅水壁虎2 小时前
vue基础(第二章 )
前端·javascript·vue.js
界面开发小八哥2 小时前
界面控件DevExtreme v26.1新版亮点——支持Angular 22
前端·javascript·angular.js·devexpress·ui开发·devextreme
Getflare2 小时前
前端 + UI 设计 + AI:这不是三个工种,是一个新三角能力模型(附自检清单)
前端·人工智能·ui
oil欧哟2 小时前
我做了一个 Vibe Coding 术语学习站:VibeHub
前端·ai·agent·独立开发·vibe coding
审小匠OpenCPAi3 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
Revolution613 小时前
一个公共表格组件,是怎么一步步失控的
前端·前端工程化
mONESY3 小时前
React useState 核心原理与最佳实践:从异步更新到性能优化全解
javascript