Lodash 源码阅读-dropRightWhile
概述
dropRightWhile
是一个从数组末尾开始删除元素的函数,但不是简单地删掉固定数量,而是根据条件判断删到什么位置。只要元素满足条件就删,直到遇到第一个不满足条件的元素才停下来。
前置学习
依赖函数
- baseWhile:内部的条件切片函数,实际干活的是它
- getIteratee:把各种类型的参数转成标准迭代函数
技术知识
- 高阶函数:函数可以作为参数传递
- 谓词函数:返回布尔值的函数,用来判断条件
- 迭代器简写:Lodash 支持的多种简写形式(对象匹配、属性匹配等)
- 从右向左处理:从数组末尾开始处理元素的技巧
- 条件切片:根据元素内容决定切片位置
源码实现
javascript
/**
* Creates a slice of `array` excluding elements dropped from the end.
* Elements are dropped 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 }
* ];
*
* _.dropRightWhile(users, function(o) { return !o.active; });
* // => objects for ['barney']
*
* // The `_.matches` iteratee shorthand.
* _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
* // => objects for ['barney', 'fred']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.dropRightWhile(users, ['active', false]);
* // => objects for ['barney']
*
* // The `_.property` iteratee shorthand.
* _.dropRightWhile(users, 'active');
* // => objects for ['barney', 'fred', 'pebbles']
*/
function dropRightWhile(array, predicate) {
return array && array.length
? baseWhile(array, getIteratee(predicate, 3), true, true)
: [];
}
实现思路
dropRightWhile
实现很简单:
- 先检查数组是否有效(存在且有长度),无效就返回空数组
- 把传入的
predicate
(条件函数)通过getIteratee
转换成标准格式 - 调用
baseWhile
函数,参数含义是:- 第一个参数:要处理的数组
- 第二个参数:处理好的条件函数
- 第三个参数:
true
表示"丢弃"模式(而不是"保留"模式) - 第四个参数:
true
表示从右向左处理(从末尾开始)
baseWhile
会从数组末尾开始,把满足条件的元素都删掉,直到遇到不满足条件的元素
源码解析
空值检查与简洁表达
javascript
return array && array.length
? baseWhile(array, getIteratee(predicate, 3), true, true)
: [];
这行代码看着简单,其实包含了很多逻辑:
array && array.length
一次性检查了两件事:- 数组是否存在(不是
null
或undefined
) - 数组是否有长度(不是空数组)
- 数组是否存在(不是
- 如果检查失败,直接返回空数组
[]
- 三元运算符
? :
让代码非常简洁,避免了if/else
的冗余
迭代器处理
javascript
getIteratee(predicate, 3);
这部分隐藏了很多智能处理:
getIteratee
会根据predicate
的类型返回不同的函数:- 如果是函数,原样返回
- 如果是对象,返回一个检查对象属性是否匹配的函数
- 如果是数组
[属性, 值]
,返回一个检查指定属性是否等于指定值的函数 - 如果是字符串,返回一个获取对象该属性值的函数
- 参数
3
表示生成的函数会接收三个参数:元素值、索引和原数组
这种设计让 dropRightWhile
支持多种简洁的写法,大大提高了使用灵活性。
baseWhile 的调用
baseWhile(array, getIteratee(predicate, 3), true, true)
这个调用中最关键的是后两个参数:
- 第三个参数
true
表示 "drop" 模式,即丢弃满足条件的元素 - 第四个参数
true
表示从右向左处理,这是dropRightWhile
区别于dropWhile
的关键
baseWhile
大致的工作流程是:
- 确定迭代起点(从右向左则从数组末尾开始)
- 不断检查元素是否满足条件
- 满足条件就继续检查下一个
- 一旦遇到不满足条件的元素,就停止迭代
- 根据是 "drop" 还是 "take" 模式以及迭代方向,返回对应的数组切片
总结
dropRightWhile
是一个简单但很实用的函数,它有这些特点:
-
条件过滤 - 不是机械地删除固定数量,而是根据元素内容智能决定
-
方向性 - 专门处理从右向左(从末尾开始)的场景,与
dropWhile
形成互补 -
灵活的条件表达 - 支持多种形式的条件判断,从函数到对象再到属性名
-
不可变操作 - 不修改原数组,符合函数式编程理念
常见应用场景包括:删除数据末尾的无效记录、清理文本末尾的特殊字符、取得最近一个特定事件之前的所有记录等。
通过简单的条件表达式,dropRightWhile
让"从末尾删除满足某个条件的元素"这个操作变得优雅而直观,避免了手写循环和复杂判断逻辑。