Lodash 源码阅读-takeRightWhile
概述
takeRightWhile
函数用于从数组末尾提取元素,直到遇到第一个不满足条件的元素为止。它不是简单地提取固定数量元素,而是根据条件动态决定提取哪些元素,特别适合从数据末尾获取满足特定条件的连续元素。
前置学习
依赖函数
- baseWhile:提供条件数组切片的内部函数
- getIteratee:转换各种形式谓词为标准函数的工具
技术知识
- 高阶函数:接收函数作为参数的编程方式
- 谓词函数:返回布尔值的判断函数
- 迭代器简写:Lodash 中的简写表达式
- 数组切片:创建数组子集的操作
- 从右向左迭代:从数组末尾开始处理元素
源码实现
javascript
/**
* Creates a slice of `array` with elements taken from the end. 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': true },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': false }
* ];
*
* _.takeRightWhile(users, function(o) { return !o.active; });
* // => objects for ['fred', 'pebbles']
*
* // The `_.matches` iteratee shorthand.
* _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
* // => objects for ['pebbles']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.takeRightWhile(users, ['active', false]);
* // => objects for ['fred', 'pebbles']
*
* // The `_.property` iteratee shorthand.
* _.takeRightWhile(users, 'active');
* // => []
*/
function takeRightWhile(array, predicate) {
return array && array.length
? baseWhile(array, getIteratee(predicate, 3), false, true)
: [];
}
实现思路
takeRightWhile
实现非常直接:先检查数组是否有效,然后调用 baseWhile
函数处理具体逻辑。传给 baseWhile
的四个参数分别是:原数组、转换后的谓词函数、操作模式(false 表示"提取")和方向标识(true 表示"从右向左")。这个函数从数组末尾开始,连续提取满足条件的元素,直到遇到第一个不满足条件的元素。
源码解析
参数检查
javascript
array && array.length ? ... : []
这行代码处理边界情况:
- 如果数组为
null
、undefined
或空数组,直接返回空数组 - 用短路表达式简洁地处理无效输入
例如:
javascript
_.takeRightWhile(null, (x) => x > 0); // => []
_.takeRightWhile([], (x) => x > 0); // => []
迭代器处理
javascript
getIteratee(predicate, 3);
这部分负责将各种形式的谓词转换为标准函数:
- 数字
3
表示迭代函数接收三个参数:值、索引、原数组 - 支持四种谓词形式:
- 函数形式:如
x => !x.active
- 对象匹配形式:如
{user: 'pebbles', active: false}
- 属性值匹配形式:如
['active', false]
- 属性访问形式:如
'active'
(检查属性是否为真值)
- 函数形式:如
这种灵活性大大提高了函数的易用性:
javascript
// 四种等效写法
_.takeRightWhile(users, (user) => !user.active);
_.takeRightWhile(users, { active: false });
_.takeRightWhile(users, ["active", false]);
_.takeRightWhile(users, "active"); // 提取属性为真的元素
baseWhile 调用
javascript
baseWhile(array, getIteratee(predicate, 3), false, true);
这是函数核心:
- 第一个参数是输入数组
- 第二个参数是转换后的迭代函数
- 第三个参数
false
指定为"take"模式(保留满足条件的元素) - 第四个参数
true
指定从右向左处理(从末尾开始)
baseWhile
的工作流程:
- 从数组末尾开始向前迭代
- 对每个元素应用谓词函数
- 只要谓词返回
true
,就将元素加入结果 - 一遇到谓词返回
false
的元素,立即停止
例如对数组 [1, 2, 3, 4, 5]
和条件 x => x > 3
:
- 从末尾元素 5 开始:满足条件,保留
- 元素 4:满足条件,保留
- 元素 3:不满足条件,停止
- 结果是
[4, 5]
注意结果数组中的元素保持原数组的顺序,不会被反转。
总结
takeRightWhile
函数是 Lodash 中处理数组的实用工具,它体现了以下设计原则:
- 方向性处理:支持从右向左(从末尾开始)处理数组
- 声明式编程:用简洁的方式表达"取出什么"而非"如何取出"
- 功能对称性 :与
takeWhile
形成对称操作,一个从头处理,一个从尾处理 - 不可变性:创建新数组而非修改原数组,避免副作用
这个函数在处理时间序列数据、日志文件分析、状态追踪等场景下特别有用,让开发者能用简洁代码提取数组末尾满足条件的连续元素。