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 保持简洁明了。

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax