Lodash 源码阅读-pullAt
概述
pullAt
是 Lodash 中的一个数组操作函数,用于移除数组中指定索引位置的元素,并返回由被移除元素组成的新数组。与其他数组操作函数不同,pullAt
会直接修改原数组(即具有副作用),这使得它在需要同时获取被移除元素并更新原数组的场景中特别有用。
前置学习
依赖函数
flatRest
:将函数的 rest 参数展平的特殊版本baseAt
:根据指定的路径从对象中获取值的基础实现basePullAt
:从数组中移除指定索引位置元素的基础实现arrayMap
:数组映射函数,类似于Array.prototype.map
isIndex
:检查一个值是否是有效的数组索引compareAscending
:用于升序排序的比较函数
技术知识
- 函数包装与高阶函数:理解
flatRest
如何包装函数 - 数组操作:了解数组元素的移除及相关操作
- 类型转换:了解如何使用一元加号 (
+
) 将值转换为数字 - 排序算法:了解为什么需要对索引进行排序
源码实现
javascript
var pullAt = flatRest(function (array, indexes) {
var length = array == null ? 0 : array.length,
result = baseAt(array, indexes);
basePullAt(
array,
arrayMap(indexes, function (index) {
return isIndex(index, length) ? +index : index;
}).sort(compareAscending)
);
return result;
});
实现思路
pullAt
函数的实现思路可以分为三个主要步骤:
- 提取要移除的元素:使用
baseAt
函数从原数组中获取指定索引处的元素,并将这些元素作为结果数组保存 - 处理索引:将所有索引转换为合适的格式(确保数字索引)并按升序排序
- 移除元素:使用
basePullAt
函数从原数组中按照处理后的索引移除元素
这种实现确保了即使在移除多个元素的情况下,也能正确地维护索引关系,避免因为数组长度变化导致的索引错位问题。
源码解析
函数包装
javascript
var pullAt = flatRest(function (array, indexes) {
// 函数体...
});
pullAt
使用 flatRest
函数包装,这意味着它接受可变数量的参数,并将第一个参数后的所有参数合并为一个展平的数组。例如:
pullAt(array, 1, 2, 3)
中,indexes
会被处理为[1, 2, 3]
pullAt(array, [1, 2], [3])
中,indexes
会被处理为[1, 2, 3]
这种设计使函数调用更加灵活。
初始化变量
javascript
var length = array == null ? 0 : array.length,
result = baseAt(array, indexes);
这段代码做了两件事:
- 获取数组长度:如果
array
是null
或undefined
,则设置length
为 0,否则获取数组的实际长度 - 使用
baseAt
函数获取指定索引处的元素值:这些值将作为函数的返回值
处理索引并移除元素
javascript
basePullAt(
array,
arrayMap(indexes, function (index) {
return isIndex(index, length) ? +index : index;
}).sort(compareAscending)
);
这段代码负责从数组中移除元素,主要步骤为:
-
处理索引:使用
arrayMap
遍历indexes
数组- 对于每个索引,检查它是否是有效的数组索引(使用
isIndex
函数) - 如果是有效索引,使用一元加号 (
+
) 将其转换为数字(处理字符串索引如 "1") - 如果不是有效索引,保持原样(可能是属性路径)
- 对于每个索引,检查它是否是有效的数组索引(使用
-
排序索引:使用
compareAscending
函数对索引进行升序排序- 这一步很重要,因为从数组中移除元素时,较大索引处的元素应该先被移除,以避免索引错位
-
移除元素:调用
basePullAt
函数,根据排序后的索引从数组中移除元素
返回结果
javascript
return result;
最后,函数返回由被移除元素组成的数组,这个数组是在函数开始时通过 baseAt
计算的。
总结
pullAt
函数是 Lodash 中一个强大的数组操作工具,它允许开发者同时完成两个操作:
- 从数组中移除指定索引处的元素(修改原数组)
- 获取被移除的元素(返回新数组)
这种设计体现了几个重要的编程原则:
- 分治策略:将复杂操作分解为获取元素和移除元素两个步骤,分别由专门的函数处理
- 索引排序:通过对索引进行排序,确保在有多个索引时能够正确处理元素移除
- 类型处理:对索引进行类型检查和转换,增强函数的健壮性
- API 设计 :使用
flatRest
提供灵活的参数格式,改善用户体验
虽然直接修改原数组违背了函数式编程中的不可变性原则,但这种设计对于需要同时获取移除元素和更新原数组的场景非常有用,提供了简洁的解决方案。如果需要保持原数组不变,可以先复制数组,然后对副本使用 pullAt
。