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