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. 高效实现:通过精心设计的循环和条件判断,确保性能最优
相关推荐
赵大仁1 小时前
微前端框架选型指南
前端·架构·前端框架
GISer_Jing1 小时前
阿里云前端Nginx部署完,用ip地址访问却总访问不到,为什么?检查安全组是否设置u为Http(80)!
前端·nginx·阿里云
爱笑的眼睛116 小时前
uniapp 云开发全集 云数据库
javascript·数据库·oracle·uni-app
赵大仁6 小时前
微前端统一状态树实现方案
前端·前端框架
阿珊和她的猫8 小时前
钩子函数和参数:Vue组件生命周期中的自定义逻辑
前端·javascript·vue.js
勘察加熊人8 小时前
vue展示graphviz和dot流程图
前端·vue.js·流程图
软件2058 小时前
【登录流程图】
java·前端·流程图
2501_915373889 小时前
Electron 从零开始:构建你的第一个桌面应用
前端·javascript·electron
贩卖黄昏的熊10 小时前
JavaScript 笔记 --- part8 --- JS进阶 (part3)
前端·javascript·笔记
CodeCipher10 小时前
Java后端程序员学习前端之CSS
前端·css·学习