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 保持简洁易用,同时内部实现可以更加复杂和高效。

相关推荐
Rudon滨海渔村3 分钟前
【Tauri】桌面程序exe开发 - Tauri+Vue开发Windows应用 - 比Electron更轻量!8MB!
javascript·electron·tauri·桌面应用
cg50177 分钟前
Vue回调函数中的this
前端·javascript·vue.js
前端太佬9 分钟前
从零到一实现扫码登录:一个前端菜鸟的踩坑实录
前端·javascript·架构
yuanmenglxb200420 分钟前
微信小程序核心技术栈
前端·javascript·vue.js·笔记·微信小程序·小程序
爱编程的鱼20 分钟前
如何让 HTML 文件嵌入另一个 HTML 文件:详解与实践
前端·html
_092725 分钟前
Vue 2 与 Vue 3 的核心区别及 Vue 3 新特性详解
前端
David凉宸26 分钟前
一文带你使用Vue完成移动端(apk)项目
前端
纪元A梦36 分钟前
华为OD机试真题——绘图机器(2025A卷:100分)Java/python/JavaScript/C++/C/GO最佳实现
java·javascript·c++·python·华为od·go·华为od机试题
会飞的鱼先生38 分钟前
Vue3的内置组件 -实现过渡动画 TransitionGroup
前端·javascript·vue.js·vue
晓得迷路了39 分钟前
10 分钟开发一个 Chrome 插件?Trae 让你轻松实现!
前端·javascript·trae