Lodash源码阅读-pullAllWith

Lodash 源码阅读-pullAllWith

概述

pullAllWith 是 Lodash 库中的一个数组操作函数,用于从数组中移除指定的元素。它的特别之处在于可以接收一个自定义的比较器(comparator)函数,通过这个函数来决定哪些元素应该被移除。与其他数组差异函数不同,pullAllWith 会直接修改原数组,是一个具有副作用的函数。

前置学习

依赖函数

  • basePullAll:核心实现函数,负责实际的数组元素移除操作
  • baseIndexOfWith:支持自定义比较器的数组元素查找函数
  • baseIndexOf:基础的数组索引查找函数

技术知识

  • 数组操作:数组元素的删除和查找
  • 高阶函数:函数作为参数传递
  • 比较器模式:通过自定义比较逻辑来处理复杂对象的比较
  • 函数式编程:不可变性与副作用

源码实现

js 复制代码
function pullAllWith(array, values, comparator) {
  return array && array.length && values && values.length
    ? basePullAll(array, values, undefined, comparator)
    : array;
}

实现思路

pullAllWith 的实现非常简洁。函数首先检查输入数组和目标值数组是否都存在且非空,如果条件满足,则调用内部的 basePullAll 函数执行实际的移除操作,其中第三个参数(迭代器)传入 undefined,第四个参数传入自定义比较器。这种设计将核心逻辑委托给专门的内部函数,保持了公共 API 的简洁性和易用性。

源码解析

函数签名:

js 复制代码
function pullAllWith(array, values, comparator)
  • array:要修改的数组
  • values:包含要移除元素的数组
  • comparator:自定义比较器函数,接收两个参数(arrVal, othVal),用于比较数组元素

函数主体:

js 复制代码
return array && array.length && values && values.length
  ? basePullAll(array, values, undefined, comparator)
  : array;

这行代码包含以下关键部分:

  1. 参数校验array && array.length && values && values.length

    这是一个简洁的条件表达式,用于检查:

    • array 存在且有长度(不是空数组)
    • values 存在且有长度(不是空数组)

    这种检查方式可以避免在无需处理的情况下调用复杂的内部函数,提高了效率。

  2. 调用内部实现basePullAll(array, values, undefined, comparator)

    当条件满足时,调用 basePullAll 函数进行实际操作:

    • 第一个参数 array 是要修改的数组
    • 第二个参数 values 是包含要移除元素的数组
    • 第三个参数传入 undefined,表示不使用迭代器
    • 第四个参数传入用户提供的 comparator 比较器函数
  3. 返回修改后的数组

    • 如果条件不满足,直接返回原始 array
    • 如果条件满足,返回 basePullAll 处理后的 array(由于是直接修改,实际上返回的就是原数组的引用)

basePullAll 的核心实现:

pullAllWith 调用 basePullAll 时,内部会根据是否提供了比较器来选择不同的查找方法:

js 复制代码
var indexOf = comparator ? baseIndexOfWith : baseIndexOf;

如果提供了比较器,就使用 baseIndexOfWith 函数,它会在每次比较元素时调用自定义比较器。这使得 pullAllWith 能够支持复杂对象的比较,而不仅限于简单值的严格相等比较。

使用示例

js 复制代码
// 使用 _.isEqual 作为比较器移除对象
var array = [
  { x: 1, y: 2 },
  { x: 3, y: 4 },
  { x: 5, y: 6 },
];
_.pullAllWith(array, [{ x: 3, y: 4 }], _.isEqual);
console.log(array);
// => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]

// 自定义比较器 - 只比较x属性
var array = [
  { x: 1, y: 2 },
  { x: 3, y: 4 },
  { x: 5, y: 6 },
];
_.pullAllWith(array, [{ x: 3 }], (arrVal, othVal) => arrVal.x === othVal.x);
console.log(array);
// => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]

// 在不存在的情况下不会修改数组
var emptyArray = [];
_.pullAllWith(emptyArray, [1, 2, 3], _.isEqual);
console.log(emptyArray);
// => []

// 如果values为空,也不会修改数组
var array = [1, 2, 3];
_.pullAllWith(array, [], _.isEqual);
console.log(array);
// => [1, 2, 3]

总结

  1. 灵活的比较能力pullAllWith 通过支持自定义比较器,极大地提升了数组操作的灵活性,能够应对复杂对象的比较场景。

  2. 副作用设计 :与许多 Lodash 函数不同,pullAllWith 直接修改原数组,这种设计在某些场景下可以提高性能,但使用时需要注意它会改变输入数组。

  3. 优雅的参数校验:函数使用简洁的条件表达式进行参数校验,避免了冗长的 if 语句,同时保证了代码的健壮性。

  4. 分层设计 :将核心逻辑委托给专门的内部函数 basePullAll,体现了良好的代码分层和职责分离,使公共 API 保持简洁明了。

相关推荐
程序员黑豆4 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
To_OC4 小时前
踩了个 TS 的坑之后,我终于把 type 和 interface 掰明白了
前端·react.js·typescript
GreenTea5 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
浮生望5 小时前
前端API工程化:用 Mock 数据与 Axios 配置实现独立于后端的并行开发
前端
万少5 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端
波波0075 小时前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
Brown.alexis6 小时前
es6知识点1-自备使用
前端·ecmascript·es6
小爬的老粉丝7 小时前
JavaScript 纯前端预览 WPS:先识别容器,再路由解析器
前端·javascript·wps
计算机魔术师8 小时前
新兴多智能体系统的模式与问题
前端
用户059540174468 小时前
AI Agent 上下文污染踩坑实录:用 pytest + Redis 揪出 3 类记忆串号 bug,排查 6 小时
前端·css