Lodash源码阅读-takeWhile

Lodash 源码阅读-takeWhile

概述

takeWhile 函数从数组开头开始取元素,但不是简单地取固定数量,而是根据条件判断取到哪里停止。只要元素满足条件就继续取,一旦遇到第一个不满足条件的元素就立即停下来。简单说就是"一路取,遇到不符合的就停"。

前置学习

依赖函数

  • baseWhile:内部的条件切片函数,实际干活的是它
  • getIteratee:把各种类型的参数转成标准迭代函数

技术知识

  • 高阶函数:函数可以作为参数传递
  • 谓词函数:返回布尔值的函数,用来判断条件
  • 迭代器简写:Lodash 支持的多种条件表达方式
  • 短路处理:一旦条件不满足就立即停止处理
  • 函数柯里化:预处理函数参数,提高复用性

源码实现

javascript 复制代码
/**
 * Creates a slice of `array` with elements taken from the beginning. Elements
 * are taken until `predicate` returns falsey. The predicate is invoked with
 * three arguments: (value, index, array).
 *
 * @static
 * @memberOf _
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to query.
 * @param {Function} [predicate=_.identity] The function invoked per iteration.
 * @returns {Array} Returns the slice of `array`.
 * @example
 *
 * var users = [
 *   { 'user': 'barney',  'active': false },
 *   { 'user': 'fred',    'active': false },
 *   { 'user': 'pebbles', 'active': true }
 * ];
 *
 * _.takeWhile(users, function(o) { return !o.active; });
 * // => objects for ['barney', 'fred']
 *
 * // The `_.matches` iteratee shorthand.
 * _.takeWhile(users, { 'user': 'barney', 'active': false });
 * // => objects for ['barney']
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.takeWhile(users, ['active', false]);
 * // => objects for ['barney', 'fred']
 *
 * // The `_.property` iteratee shorthand.
 * _.takeWhile(users, 'active');
 * // => []
 */
function takeWhile(array, predicate) {
  return array && array.length
    ? baseWhile(array, getIteratee(predicate, 3))
    : [];
}

实现思路

takeWhile 的实现非常直观:

  1. 先检查数组是否有效(存在且有长度),无效就返回空数组
  2. 把传入的 predicate(条件函数)通过 getIteratee 转换成标准格式
  3. 调用 baseWhile 函数,不传第三个参数(默认是 false),表示这是"提取"模式而不是"丢弃"模式
  4. baseWhile 会从数组开头开始,把满足条件的元素都收集起来,直到遇到不满足条件的元素

源码解析

空值检查与简洁表达

javascript 复制代码
return array && array.length ? baseWhile(array, getIteratee(predicate, 3)) : [];

这一行代码看起来很简单,但做了很多事情:

  • array && array.length 检查了两件事:
    1. 数组是否存在(不是 nullundefined
    2. 数组是否有长度(不是空数组)
  • 三元运算符 ? : 让代码非常简洁
  • 如果检查失败,直接返回空数组 []

迭代器处理

javascript 复制代码
getIteratee(predicate, 3);

这部分代码非常智能,能处理多种形式的条件:

  • getIteratee 会根据 predicate 的类型返回不同的函数:
    • 如果是函数:直接使用
    • 如果是对象:返回一个检查对象属性是否匹配的函数
    • 如果是数组 [属性, 值]:返回一个检查指定属性是否等于指定值的函数
    • 如果是字符串:返回一个获取对象该属性值的函数
  • 参数 3 表示生成的函数会接收三个参数:元素值、索引和原数组

baseWhile 的调用

由于 baseWhile 没有传第三个和第四个参数,它们默认都是 false,这意味着:

  • 第三个参数 false 表示 "take" 模式,即保留满足条件的元素(而不是丢弃)
  • 第四个参数 false 表示从左向右处理(从开头开始)

baseWhile 的工作流程大致是:

  1. 从数组开头开始遍历
  2. 对每个元素调用条件函数
  3. 如果返回 true,就把这个元素加入结果
  4. 一旦返回 false,立即停止并返回已收集的元素

总结

takeWhile 是一个简单但很实用的函数,它有这些特点:

  1. 条件截取 - 不是简单取固定数量,而是根据元素内容智能决定

  2. 短路机制 - 一旦遇到不符合条件的元素立即停止,不会遍历整个数组

  3. 灵活的条件表达 - 支持多种形式的条件判断,从函数到对象再到属性名

  4. 函数式风格 - 不修改原数组,返回新数组,避免副作用

这个函数在很多场景下都很有用,比如:

  • 提取文件头部的元数据
  • 获取连续有效的用户输入
  • 截取满足质量要求的数据序列

通过简单的条件表达式,takeWhile 让"获取满足条件的连续元素"这个操作变得优雅而直观,避免了手写循环和复杂判断逻辑。

相关推荐
三小河几秒前
解决vite环境下调用获取二进制文件流 部分文件报错 (failed)net::ERR_INVALID_HTTP_RESPONSE)
前端
好好好明天会更好1 分钟前
pinia从定义到运用
前端·vue.js
代码小学僧3 分钟前
Vite 项目最简单方法解决部署后 Failed to fetch dynamically imported Error问题
前端·vue.js·vite
RoyLin3 分钟前
TypeScript设计模式:装饰器模式
前端·后端·typescript
掘金一周13 分钟前
Flutter Riverpod 3.0 发布,大规模重构下的全新状态管理框架 | 掘金一周 9.18
前端·人工智能·后端
一涯24 分钟前
页面出现空白区域
前端
spmcor1 小时前
MinIO本地对象存储部署指南
前端
少年纪1 小时前
前端用 pdf.js 将 PDF 渲染到 Canvas 再转图片,文字消失的坑
前端
RoyLin1 小时前
TypeScript设计模式:复合模式
前端·后端·typescript
我是天龙_绍1 小时前
CSS/JS/图片全挂了,部署后页面白屏/资源加载失败?这两个配置项坑了多少人!
前端