Lodash源码阅读-pullAll

Lodash 源码阅读-pullAll

概述

pullAll 函数用于从数组中移除指定的值。与 pull 不同,pullAll 接收一个数组作为要移除的值,而不是多个独立参数。这个函数会直接修改原数组(即具有副作用),从原数组中删除所有在指定数组中出现的值,并返回修改后的原数组。

前置学习

依赖函数

  • basePullAll:核心实现函数,负责实际的数组元素移除操作

技术知识

  • 数组方法:数组的修改和引用
  • 函数参数校验:输入合法性检查
  • 引用类型:对象引用和函数参数传递

源码实现

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

实现思路

pullAll 的实现非常简洁,但很实用。它首先检查源数组和目标值数组是否都存在且非空。如果满足条件,就调用 basePullAll 函数执行实际的移除操作;否则,直接返回原数组。这种设计将核心逻辑委托给更专门的内部函数,保持了公共 API 的简洁明了。

源码解析

函数签名:

js 复制代码
function pullAll(array, values)
  • array: 要修改的数组
  • values: 包含要移除元素的数组

实现细节:

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

这行代码实际上包含几个关键部分:

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

    • 确保 array 是真值(不是 null 或 undefined)且有长度
    • 确保 values 也是真值且有长度
    • 这是一种简洁的"保护语句",避免不必要的处理
  2. 调用核心实现 :如果条件满足,调用 basePullAll(array, values)

    • 委托 basePullAll 完成实际的元素移除工作
  3. 直接返回 :如果条件不满足,直接返回原数组 array

    • 保持功能的一致性和可预测性

pullAll 的关键在于它会直接修改原数组,而不是创建新数组。它通过 basePullAll 实现其核心功能。

应用场景

  1. 数据清洗:从数据集中删除无效或不需要的值
js 复制代码
// 从用户输入中移除所有不需要的字符
let userInput = ["a", "b", "$", "c", "#", "d"];
_.pullAll(userInput, ["$", "#"]);
// userInput 现在是 ['a', 'b', 'c', 'd']
  1. 列表管理:从现有列表中移除特定的项目
js 复制代码
// 从购物车中移除已售罄的商品
let cart = ["apple", "banana", "orange", "grape"];
const soldOut = ["banana", "grape"];
_.pullAll(cart, soldOut);
// cart 现在是 ['apple', 'orange']
  1. 标签过滤:移除特定标签
js 复制代码
// 从文章标签中移除受限制的标签
let tags = ["js", "web", "nsfw", "tutorial", "violence"];
const restrictedTags = ["nsfw", "violence"];
_.pullAll(tags, restrictedTags);
// tags 现在是 ['js', 'web', 'tutorial']

总结

通过学习 pullAll 函数,我们可以看到以下设计原则:

  1. 单一职责pullAll 只负责参数校验和调用适当的实现函数,保持函数专注于单一任务。

  2. 适当的副作用 :虽然函数式编程通常避免副作用,但 pullAll 明确表示会修改原数组,这在某些场景下是有意义和高效的。

  3. 防御性编程:函数在执行核心逻辑前验证参数的有效性,增强了代码的健壮性。

  4. 委托模式 :将复杂的实现细节委托给专门的内部函数(basePullAll),使公共 API 保持简洁。

  5. 一致的返回值:无论是否执行了移除操作,函数始终返回原数组,保持接口的一致性。

pullAll 虽然实现简单,但体现了良好的函数设计理念,使其既易于使用又足够灵活和强大。

相关推荐
SoaringHeart32 分钟前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒2 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰3 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
山河木马3 小时前
渲染管线-计算得到gl_Position(顶点着色器)之后续GPU流程
javascript·webgl·图形学
竹林8184 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花4 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12275 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪5 小时前
Vue3-生命周期
前端
莪_幻尘5 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程
lichenyang4536 小时前
从 has.echo 到异步 API 注册表:一次 ASCF API 回调不触发的排查复盘
前端