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 让"获取满足条件的连续元素"这个操作变得优雅而直观,避免了手写循环和复杂判断逻辑。

相关推荐
加班是不可能的,除非双倍日工资1 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi2 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip2 小时前
vite和webpack打包结构控制
前端·javascript
excel2 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国3 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼3 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy3 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT3 小时前
promise & async await总结
前端
Jerry说前后端3 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天3 小时前
A12预装app
linux·服务器·前端