Lodash 源码阅读-basePullAt
概述
basePullAt
是 Lodash 内部的工具函数,用于从数组中移除指定索引位置的元素。它是 _.pullAt
方法的底层实现,支持同时移除多个索引位置的元素,并且会修改原数组。
前置学习
依赖函数
- isIndex: 判断一个值是否为有效的数组索引
- baseUnset: 移除对象属性的内部方法(用于非数字索引)
- splice: JavaScript 原生数组方法,用于删除数组元素
技术知识
- 数组修改操作: 原地修改数组的方法
- 函数绑定 : 使用
call
方法调用函数并绑定this
值 - 稀疏数组: JavaScript 中的非连续索引数组
- 索引处理: 数组索引与对象属性的区别
源码实现
js
function basePullAt(array, indexes) {
var length = array ? indexes.length : 0,
lastIndex = length - 1;
while (length--) {
var index = indexes[length];
if (length == lastIndex || index !== previous) {
var previous = index;
if (isIndex(index)) {
splice.call(array, index, 1);
} else {
baseUnset(array, index);
}
}
}
return array;
}
实现思路
basePullAt
函数的设计思路非常巧妙:
- 从后向前遍历索引数组,这样在删除元素时不会影响后续元素的索引位置
- 使用
isIndex
判断索引是否为有效的数组索引 - 对于有效的数组索引,使用原生的
splice
方法删除元素 - 对于非数字索引(对象属性),使用
baseUnset
方法删除 - 跳过重复的索引,避免多次尝试删除同一位置的元素
- 返回修改后的原数组
这种实现方式保证了高效的数组元素删除,并且处理了各种边界情况。
源码解析
让我们逐步解析 basePullAt
函数的实现:
js
function basePullAt(array, indexes) {
var length = array ? indexes.length : 0,
lastIndex = length - 1;
首先,函数检查 array
是否存在,如果存在,则获取 indexes
数组的长度;如果不存在,则将长度设为 0。同时计算出最后一个索引的位置。
js
while (length--) {
var index = indexes[length];
函数使用了从后向前的遍历方式(length--
),这样当删除前面的元素时,不会影响后面元素的索引位置。在每次循环中,获取当前要处理的索引值。
js
if (length == lastIndex || index !== previous) {
var previous = index;
这段代码检查当前索引是否是最后一个索引或者与前一个处理的索引不同。这是为了避免重复处理相同的索引。如果 indexes
数组中包含重复的索引,只有第一次遇到时才会执行删除操作。
js
if (isIndex(index)) {
splice.call(array, index, 1);
} else {
baseUnset(array, index);
}
根据索引类型选择不同的删除方法:
- 如果是有效的数组索引(通过
isIndex
函数判断),使用splice.call(array, index, 1)
方法从数组中删除该位置的元素。 - 如果不是有效的数组索引(可能是字符串属性名),使用
baseUnset(array, index)
方法删除该属性。
js
}
}
return array;
最后,函数返回修改后的原数组。
应用示例
js
var array = ["a", "b", "c", "d"];
basePullAt(array, [1, 3]);
// 移除索引 1 和 3 的元素
// array 变成 ['a', 'c']
var obj = { 0: "a", 1: "b", foo: "bar" };
basePullAt(obj, [1, "foo"]);
// 移除索引 1 和属性 'foo'
// obj 变成 { '0': 'a' }
总结
basePullAt
函数是一个精巧的数组元素删除工具,它具有以下几个设计亮点:
- 逆序遍历: 从后向前删除元素,避免索引位置变化导致的问题。
- 类型判断: 区分处理数组索引和对象属性,使用不同的删除方法。
- 去重处理: 避免对重复索引进行多次操作,提高效率。
- 原地修改: 直接修改原数组,不创建新数组,节省内存。
这个函数体现了 Lodash 在处理数组操作时的细致考量,包括性能优化和边界情况的处理。理解这种实现方式对于我们设计自己的数组操作函数也有很大的启发。