Lodash 源码阅读-fill
概述
fill
函数用来用指定的值填充数组,可以指定起始位置和结束位置。这个函数会修改原数组,而不是创建新数组。
前置学习
依赖函数
- baseFill:实际执行填充操作的函数
- toInteger:把起始位置和结束位置转成整数
- isIterateeCall:检测参数是否是迭代器调用格式
技术知识
- 数组操作:基本的数组修改操作
- 参数默认值:处理可选参数的默认值
- 边界处理:处理负索引和越界情况
源码实现
javascript
function fill(array, value, start, end) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
if (
start &&
typeof start != "number" &&
isIterateeCall(array, value, start)
) {
start = 0;
end = length;
}
return baseFill(array, value, start, end);
}
实现思路
fill
函数的实现流程很清晰:
- 首先检查数组是否有效,如果为空就直接返回空数组
- 然后检查
start
参数是否是特殊的迭代器调用格式(这是为了兼容 Lodash 的链式调用)- 如果是,就重置
start
为 0,end
为数组长度
- 如果是,就重置
- 最后调用
baseFill
函数执行实际的填充操作,它会:- 处理起始位置和结束位置的边界情况
- 在指定范围内用给定值替换数组元素
- 返回修改后的数组
源码解析
空值处理
javascript
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
这段代码检查数组是否为 null
或 undefined
,或者是否为空数组:
- 如果数组为
null
或undefined
,则length
为 0 - 如果数组长度为 0,直接返回空数组
- 对无效输入的防御性编程,确保函数行为可预测
迭代器调用检查
javascript
if (start && typeof start != "number" && isIterateeCall(array, value, start)) {
start = 0;
end = length;
}
这段代码处理一种特殊情况,当 start
不是数字且满足 isIterateeCall
条件时:
- 重置
start
为 0,end
为数组长度 - 这种情况通常出现在链式调用或某些 Lodash 的内部使用场景
isIterateeCall
函数检查start
是否是一个对象,且满足start[0] === value
这种模式
调用 baseFill
javascript
return baseFill(array, value, start, end);
最后调用内部的 baseFill
函数,它会:
- 将
start
和end
转换为有效的整数索引 - 处理负数索引(从数组末尾计算位置)
- 确保索引在有效范围内
- 执行实际的数组填充操作
baseFill
的核心实现是一个简单的循环:
javascript
while (start < end) {
array[start++] = value;
}
这个循环从 start
到 end
(不包括 end
)填充数组的每个位置。
总结
fill
函数虽然简单,但它具有几个重要特点:
-
修改原数组 - 它是一个会改变原数组的方法,这一点要特别注意
-
灵活的索引 - 支持指定填充的起始和结束位置,还能处理负数索引
-
边界处理 - 内部会处理各种边界情况,包括无效输入、越界索引等
这个函数在很多场景下都很有用,比如:
- 初始化特定大小的数组
- 重置数组中的一部分元素
- 创建具有特定模式的数组
使用示例:
javascript
// 用 'a' 填充整个数组
_.fill([1, 2, 3], "a");
// => ['a', 'a', 'a']
// 创建并填充数组
_.fill(Array(3), 2);
// => [2, 2, 2]
// 只填充部分数组
_.fill([4, 6, 8, 10], "*", 1, 3);
// => [4, '*', '*', 10]