Lodash 源码阅读-arrayFilter
功能概述
arrayFilter
是 Lodash 库中的一个内部工具函数,它是 _.filter
方法针对数组类型的特化实现。这个函数的主要作用是遍历数组,并根据提供的断言函数(predicate)过滤出符合条件的元素,返回一个新的数组。与公开的 _.filter
方法不同,arrayFilter
不支持迭代器简写形式,它是一个更加精简和专注的内部实现。
前置学习
依赖关系
arrayFilter
是一个相对独立的函数,它不直接依赖其他 Lodash 函数。但要理解它在 Lodash 中的应用,建议了解以下相关函数:
- filter :公开的 API,它根据集合类型选择使用
arrayFilter
或baseFilter
- baseFilter:处理非数组集合(如对象)的过滤实现
技术知识
- JavaScript 中的数组操作:遍历、过滤和创建新数组
- 断言函数(predicate):返回布尔值的函数,用于测试元素是否符合条件
- 循环和迭代:使用 while 循环进行迭代操作
源码实现
javascript
/**
* A specialized version of `_.filter` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
*/
function arrayFilter(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index];
if (predicate(value, index, array)) {
result[resIndex++] = value;
}
}
return result;
}
实现思路
arrayFilter
函数的实现思路非常直接明了,可以分为以下几个步骤:
- 初始化:创建索引变量、结果数组和结果索引
- 遍历数组:使用 while 循环遍历原数组的每个元素
- 条件判断:对每个元素应用断言函数进行测试
- 收集结果:将通过测试的元素添加到结果数组中
- 返回结果:返回包含所有通过测试元素的新数组
这种实现方式简洁高效,没有额外的检查和处理逻辑,专注于核心功能的实现。
源码解析
参数解析
javascript
function arrayFilter(array, predicate) {
函数接收两个参数:
array
:要遍历的数组,可以是 null 或 undefinedpredicate
:每次迭代调用的断言函数,它接收三个参数:当前元素值、索引和原数组
初始化变量
javascript
var index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
这段代码初始化了四个变量:
index
:遍历索引,初始值为 -1,这样在第一次循环时++index
会使其变为 0length
:数组长度,如果数组为 null 或 undefined,则长度为 0resIndex
:结果数组的当前索引,用于追踪结果数组的填充位置result
:结果数组,初始为空数组
遍历和过滤
javascript
while (++index < length) {
var value = array[index];
if (predicate(value, index, array)) {
result[resIndex++] = value;
}
}
这段代码是函数的核心部分:
- 使用 while 循环,从 0 到 length-1 遍历数组
- 获取当前索引对应的元素值
- 调用断言函数
predicate(value, index, array)
测试当前元素 - 如果断言函数返回真值(truthy),则将当前元素添加到结果数组中,并增加结果索引
这种实现方式确保了只有通过断言测试的元素才会被添加到结果数组中。
返回结果
javascript
return result;
最后,函数返回包含所有通过测试元素的新数组。
与原生方法的比较
arrayFilter
与 JavaScript 原生的 Array.prototype.filter
方法有一些相似之处和区别:
javascript
// 原生 Array.prototype.filter
Array.prototype.filter = function (callback, thisArg) {
if (this == null) {
throw new TypeError("this is null or not defined");
}
var O = Object(this);
var len = O.length >>> 0;
var A = new Array(0);
var k = 0;
var to = 0;
while (k < len) {
if (k in O) {
var kValue = O[k];
if (callback.call(thisArg, kValue, k, O)) {
A[to++] = kValue;
}
}
k++;
}
return A;
};
相似之处:
- 都使用循环遍历数组元素
- 都调用回调函数测试每个元素
- 都创建并返回一个新数组
区别:
-
错误处理:
- 原生方法会对 null 和 undefined 抛出 TypeError
arrayFilter
将 null 和 undefined 视为空数组
-
稀疏数组处理:
- 原生方法会跳过数组中的空洞(稀疏数组中未设置的元素)
arrayFilter
会处理所有索引,包括未设置的元素(将其视为 undefined)
-
this 绑定:
- 原生方法支持通过第二个参数设置回调函数的 this 值
arrayFilter
不支持设置 this 值
-
类型强制:
- 原生方法对输入进行更严格的类型检查和强制转换
arrayFilter
假设输入已经是合适的类型
总结
arrayFilter
是 Lodash 中一个简单但强大的内部工具函数,它提供了一种高效的方式来过滤数组元素。虽然它是一个内部函数,但通过 _.filter
方法,它的功能被暴露给了库的使用者。