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

相关推荐
利刃之灵14 分钟前
02-HTML结构
前端·html
小纯洁w15 分钟前
Vue和React项目中,统一监听页面错误需要结合框架提供的错误处理机制与JavaScript原生方法
javascript·vue.js·react.js
Hopebearer_20 分钟前
理解 React 的 useEffect
前端·javascript·react.js·前端框架
excel2 小时前
webpack 检出图 第 十 节 lib/ChunkGraph.js
前端
好_快2 小时前
Lodash源码阅读-parent
前端·javascript·源码阅读
shmily ....2 小时前
前端实战:基于 Vue 与 QRCode 库实现动态二维码合成与下载功能
前端·vue.js
excel2 小时前
webpack 检出图 第 九 节 lib/ChunkGraph.js
前端
好_快2 小时前
Lodash源码阅读-pullAllBy
前端·javascript·源码阅读
web守墓人6 小时前
【gpt生成-其一】以go语言为例,详细描述一下 :语法规范BNF/EBNF形式化描述
前端·gpt·golang