Lodash源码阅读-union

148 阅读2分钟

Lodash 源码阅读-union

概述

union 函数用于创建一个包含所有给定数组中唯一值的新数组。它使用 SameValueZero 进行相等性比较,结果值的顺序取决于它们在数组中首次出现的位置。

前置学习

依赖函数

  • baseRest:模拟 ES6 的剩余参数功能,处理不定数量的参数
  • baseFlatten:将嵌套数组扁平化到指定深度
  • baseUniq:对数组去重的基础实现
  • isArrayLikeObject:检查值是否为类数组对象

技术知识

  • 函数式编程中的柯里化和部分应用
  • JavaScript 中的相等性比较 (SameValueZero)
  • 数组扁平化和去重算法
  • 不定参数处理

源码实现

var union = baseRest(function (arrays) {
  return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
});

实现思路

union 函数实现采用了函数组合的方式,首先通过 baseRest 收集所有传入的数组参数,然后对这些数组进行一层扁平化处理(只处理类数组对象),最后对扁平化的结果进行去重操作。这种设计让函数可以接收任意数量的数组作为参数,并高效地合并去重,保持了值首次出现的顺序。

源码解析

1. 函数定义与参数收集

var union = baseRest(function (arrays) {
  // 函数体...
});

baseRest 在这里的作用是将 union 函数接收的所有参数收集到 arrays 数组中。这种实现使得函数可以接受任意数量的数组参数:

_.union([2, 1], [2, 3]); // [2, 1, 3]
_.union([2], [1, 2], [4, 2]); // [2, 1, 4]

当调用 _.union([2, 1], [2, 3]) 时,arrays 参数将包含 [[2, 1], [2, 3]]

2. 扁平化处理

baseFlatten(arrays, 1, isArrayLikeObject, true);

这一步将所有输入数组合并成一个一维数组:

  • arrays:要扁平化的数组集合
  • 1:扁平化深度为 1,只处理一层嵌套
  • isArrayLikeObject:过滤条件,确保只有类数组对象被处理
  • true:严格模式,只保留通过 isArrayLikeObject 检查的值

例如,输入 [[1, 2], [2, 3]] 会被扁平化为 [1, 2, 2, 3]

3. 去重操作

baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));

baseUniq 对扁平化后的数组进行去重,使用 SameValueZero 算法比较值的相等性。这意味着:

  • 它能正确处理 NaN 值(与自身比较相等)
  • 不区分 +0-0

继续上面的例子,[1, 2, 2, 3] 去重后得到 [1, 2, 3]

总结

  1. 使用函数组合实现复杂功能,每个函数专注于单一职责,提高代码可维护性
  2. 采用 baseRest 处理不定参数,比传统 arguments 操作更加优雅
  3. 通过类型检查筛选有效输入,提高函数健壮性
  4. SameValueZero 比较算法处理特殊值,比简单的 ===Array.prototype.includes() 更完善