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

相关推荐
JarvanMo1 分钟前
再见吧CocoaPods,Swift Package Manager(SPM)即将在Flutter 3.44中成为默认依赖管理器
前端
小则又沐风a8 分钟前
基础的开发工具(2)---Linux
java·linux·前端
yqcoder8 分钟前
JavaScript 事件流:从“捕获”到“冒泡”的完整旅程
服务器·前端·javascript
Csvn19 分钟前
Vue 3 Composition API 深度解析
前端·vue.js
鹏程十八少19 分钟前
11. 2026金三银四 能答对这 29 道题,你的 Android 插件化就算真正通关了
前端·后端·面试
潇凝子潇1 小时前
使用英伟达免费调用多家大模型API
java·前端·javascript
旷世奇才李先生1 小时前
Vue 3\+Vite\+Pinia实战:前端工程化与组件化开发全指南
前端·vue.js
Beginner x_u1 小时前
前端八股整理(手写 01)|Promise 超时控制、红绿灯与 Promise.all
前端·javascript·promise
万少10 小时前
Vibe Coding不停歇,移动端 TRAE SOLO 让你用手机也能编程啦
前端·javascript·后端
kyriewen1111 小时前
WebAssembly:前端界的“外挂”,让C++代码在浏览器里跑起来
开发语言·前端·javascript·c++·单元测试·ecmascript