Lodash 源码阅读-pull
概述
pull
函数是 Lodash 中用于数组操作的实用工具,它通过原地移除数组中指定的值并返回修改后的数组。内部实现通过 baseRest
包装 pullAll
函数,使其能接收多个独立参数而非数组,提供了更灵活的调用方式。
前置学习
依赖函数
- baseRest:内部工具函数,模拟 ES6 剩余参数功能,处理不定数量参数
- pullAll:核心实现函数,接收一个数组作为要移除的值列表
- basePullAll:最底层实现函数,执行实际的数组元素移除操作
技术知识
- 数组原地修改:直接修改原数组而非创建新数组
- 函数柯里化:将接受多个参数的函数转变为接受单一参数的函数序列
- 参数处理:处理函数不定长参数
- SameValueZero:ECMAScript 规范中的相等比较算法
- 函数组合:复用已有函数创建新功能
源码实现
js
var pull = baseRest(pullAll);
实现思路
pull
函数设计简洁而精妙,通过以下方式实现:
- 使用
baseRest
函数包装pullAll
,实现参数格式转换 - 当调用
pull(array, a, b, c)
时,baseRest
将参数a, b, c
收集为数组 - 这个数组作为第二个参数传给
pullAll
函数 pullAll
再调用basePullAll
执行实际的数组元素移除操作- 整个过程直接修改原数组并返回修改后的数组
这种设计将核心逻辑委托给专用函数,同时提供灵活的参数接口,体现了良好的函数组合和复用思想。
源码解析
函数签名:
js
function pull(array, ...values)
array
: 要修改的数组...values
: 要移除的值(可变参数)
实现原理:
js
var pull = baseRest(pullAll);
这个简洁的一行代码实际上包含了丰富的细节:
-
函数转换 :
baseRest
创建一个新函数,该函数可以收集除第一个参数外的所有参数为数组js// 当调用 pull(array, 1, 2, 3) 时 // baseRest 将其转换为等效的 pullAll(array, [1, 2, 3]);
-
参数处理机制 :
baseRest
内部工作流程- 将参数分割为固定参数和剩余参数
- 应用函数将剩余参数转为数组
- 使用
apply
方法调用原函数
-
复用现有函数 :完全复用
pullAll
的逻辑,避免代码重复 -
函数特性保留 :
baseRest
还通过setToString
保留了原函数的字符串表示,便于调试
应用场景
- 移除特定值:
js
// 从数组中移除特定值
const array = [1, 2, 3, 1, 2, 3];
pull(array, 2, 3);
console.log(array); // [1, 1]
- 数据清理:
js
// 清理数组中的无效值
const data = ["valid", null, "valid", undefined, "valid", ""];
pull(data, null, undefined, "");
console.log(data); // ['valid', 'valid', 'valid']
- 数组过滤:
js
// 从数组中过滤掉多个值
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
pull(numbers, 2, 4, 6, 8);
console.log(numbers); // [1, 3, 5, 7, 9]
- 批量删除:
js
// 批量删除数组中的元素
const items = ["apple", "banana", "orange", "apple", "pear"];
const toRemove = ["apple", "pear"];
pull(items, ...toRemove);
console.log(items); // ['banana', 'orange']
总结
pull
函数体现了 Lodash 的设计哲学和几个重要的编程思想:
-
接口设计:提供简洁直观的 API,同时保持内部实现的复杂性
-
函数组合 :通过组合
baseRest
和pullAll
创建新功能,符合函数式编程原则 -
代码复用:避免重复实现类似功能,复用已有函数
-
原地修改:直接修改原数组而非创建新数组,适用于特定性能优化场景
-
参数灵活性:支持多种参数传递方式,提升使用便利性
-
关注点分离:将参数处理和核心逻辑分开,各司其职
通过对 pull
函数的学习,我们不仅了解了这个实用工具的工作原理,还能体会到 Lodash 库中优秀的设计模式和编程实践。