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
的实现非常直观:
- 先检查数组是否有效(存在且有长度),无效就返回空数组
- 把传入的
predicate
(条件函数)通过getIteratee
转换成标准格式 - 调用
baseWhile
函数,不传第三个参数(默认是false
),表示这是"提取"模式而不是"丢弃"模式 baseWhile
会从数组开头开始,把满足条件的元素都收集起来,直到遇到不满足条件的元素
源码解析
空值检查与简洁表达
javascript
return array && array.length ? baseWhile(array, getIteratee(predicate, 3)) : [];
这一行代码看起来很简单,但做了很多事情:
array && array.length
检查了两件事:- 数组是否存在(不是
null
或undefined
) - 数组是否有长度(不是空数组)
- 数组是否存在(不是
- 三元运算符
? :
让代码非常简洁 - 如果检查失败,直接返回空数组
[]
迭代器处理
javascript
getIteratee(predicate, 3);
这部分代码非常智能,能处理多种形式的条件:
getIteratee
会根据predicate
的类型返回不同的函数:- 如果是函数:直接使用
- 如果是对象:返回一个检查对象属性是否匹配的函数
- 如果是数组
[属性, 值]
:返回一个检查指定属性是否等于指定值的函数 - 如果是字符串:返回一个获取对象该属性值的函数
- 参数
3
表示生成的函数会接收三个参数:元素值、索引和原数组
baseWhile 的调用
由于 baseWhile
没有传第三个和第四个参数,它们默认都是 false
,这意味着:
- 第三个参数
false
表示 "take" 模式,即保留满足条件的元素(而不是丢弃) - 第四个参数
false
表示从左向右处理(从开头开始)
baseWhile
的工作流程大致是:
- 从数组开头开始遍历
- 对每个元素调用条件函数
- 如果返回
true
,就把这个元素加入结果 - 一旦返回
false
,立即停止并返回已收集的元素
总结
takeWhile
是一个简单但很实用的函数,它有这些特点:
-
条件截取 - 不是简单取固定数量,而是根据元素内容智能决定
-
短路机制 - 一旦遇到不符合条件的元素立即停止,不会遍历整个数组
-
灵活的条件表达 - 支持多种形式的条件判断,从函数到对象再到属性名
-
函数式风格 - 不修改原数组,返回新数组,避免副作用
这个函数在很多场景下都很有用,比如:
- 提取文件头部的元数据
- 获取连续有效的用户输入
- 截取满足质量要求的数据序列
通过简单的条件表达式,takeWhile
让"获取满足条件的连续元素"这个操作变得优雅而直观,避免了手写循环和复杂判断逻辑。