Lodash源码阅读-uniqBy

Lodash 源码阅读-uniqBy

概述

uniqBy 函数用于创建一个数组的去重版本,通过指定的迭代器函数为数组的每个元素生成用于比较的标准。它只保留数组中每个元素(基于迭代器返回值)的第一次出现。结果数组中元素的顺序取决于它们在原数组中首次出现的位置。

前置学习

依赖函数

  • baseUniq:内部函数,实现数组去重的核心逻辑
  • getIteratee:获取适当的迭代器函数

技术知识

  • 数组去重算法
  • 高阶函数:接收函数作为参数
  • 迭代器函数:为每个数组元素生成比较标准
  • JavaScript 中的 SameValueZero 比较
  • 函数柯里化和函数式编程

源码实现

javascript 复制代码
function uniqBy(array, iteratee) {
  return array && array.length ? baseUniq(array, getIteratee(iteratee, 2)) : [];
}

实现思路

uniqBy 函数的实现非常简洁,但功能强大。它首先检查输入数组是否存在且有长度,如果是,则调用内部的 baseUniq 函数进行实际的去重操作;否则返回空数组。

在调用 baseUniq 时,它传入了两个参数:

  1. 原始数组 array
  2. 通过 getIteratee(iteratee, 2) 获取的迭代器函数,其中 2 表示迭代器函数应接收一个参数(数组元素)

uniqBy 的核心在于允许用户自定义如何生成比较元素唯一性的标准,这使得去重过程更加灵活和强大。

源码解析

让我们逐行分析 uniqBy 函数的实现:

javascript 复制代码
function uniqBy(array, iteratee) {

函数定义,接收两个参数:

  • array:要去重的数组
  • iteratee:迭代器函数,为每个元素生成比较的键值
javascript 复制代码
return array && array.length ? baseUniq(array, getIteratee(iteratee, 2)) : [];

这行代码完成了主要工作:

  1. array && array.length 检查数组是否存在且有长度
  2. 如果条件为真,调用 baseUniq 函数
    • 第一个参数是原始数组 array
    • 第二个参数是通过 getIteratee(iteratee, 2) 获取的迭代器函数
  3. 如果条件为假(数组不存在或为空),返回空数组 []

getIteratee(iteratee, 2) 是个关键部分,它根据传入的 iteratee 类型返回一个适当的函数:

  • 如果 iteratee 是函数,它会被直接使用
  • 如果 iteratee 是字符串,它会被转换为属性访问函数(如 _.property 的效果)
  • 如果 iteratee 是对象,它会被转换为匹配器函数(如 _.matches 的效果)
  • 如果 iteratee 是数组,它会被转换为属性-值匹配函数(如 _.matchesProperty 的效果)
  • 如果 iteratee 为 null 或 undefined,会返回 identity 函数(返回原值)

参数 2 表示返回的迭代器函数的参数数量 (arity),这里指定为接收一个参数。

baseUniq 执行时,它会使用这个迭代器函数为每个数组元素计算一个 "键",然后使用这些键来确定元素是否唯一。相同键的元素中,只有第一个会被保留在结果数组中。

总结

uniqBy 函数是 Lodash 的一个实用工具,通过允许自定义比较标准,它提供了比简单的 uniq 函数更强大的数组去重能力。

这个函数的主要特点包括:

  1. 灵活性:支持多种形式的迭代器(函数、字符串路径、对象匹配器等)
  2. 保留原始值:虽然比较是基于迭代器返回的值,但结果数组中保留的是原始元素
  3. 保持顺序:保留了元素在原数组中的相对顺序(首次出现的位置)
  4. 参数验证:优雅地处理边缘情况,如空数组或 null 值

在实际应用中,uniqBy 特别适用于:

  • 去除具有相同特定属性值的对象
  • 基于复杂计算进行去重
  • 实现类似 SQL 中的 "GROUP BY" 功能(取每组第一个元素)

从设计模式角度看,uniqBy 使用了策略模式(允许用户选择不同的去重策略)和委托模式(将具体实现委托给内部函数)。这种设计让 API 保持简洁易用,同时内部实现可以更加复杂和高效。

相关推荐
贵沫末2 分钟前
React——基础
前端·react.js·前端框架
aklry14 分钟前
uniapp三步完成一维码的生成
前端·vue.js
Rubin9321 分钟前
判断元素在可视区域?用于滚动加载,数据埋点等
前端
爱学习的茄子22 分钟前
AI驱动的单词学习应用:从图片识别到语音合成的完整实现
前端·深度学习·react.js
用户38022585982422 分钟前
使用three.js实现3D地球
前端·three.js
程序无bug25 分钟前
Spring 面向切面编程AOP 详细讲解
java·前端
zhanshuo25 分钟前
鸿蒙UI开发全解:JS与Java双引擎实战指南
前端·javascript·harmonyos
JohnYan25 分钟前
模板+数据的文档生成技术方案设计和实现
javascript·后端·架构
撰卢1 小时前
如何提高网站加载速度速度
前端·javascript·css·html
10年前端老司机1 小时前
在React项目中如何封装一个可扩展,复用性强的组件
前端·javascript·react.js