本篇继续分析下 uniq
和 union
家族的方法,uniq
方法主要是将数组去重,union
方法主要是将多个数组聚合成一个数组并去重。包括uniq
、uniqBy
、uniqWith
、union
、unionBy
、unionWith
、以及核心方法baseUniq
、bashFlatten
。并说明下在 lodash
中by
、with
这两个后缀的区别。
对应源码分析已推到 github
仓库: https://github.com/MageeLin/lodash-source-code-analysis
uniq
和 union
家族方法的依赖路径图如下所示,其实只用看左半部分,右半部分的代码已经在之前的文章中分析过。
lodash 中的后缀
在 lodash
的方法中,同一家族的方法都是用后缀来区别开的,比如本篇中的 uniqBy
、uniqWith
。仔细翻了下所有的方法,最常用的后缀就是下表这几个:
后缀 | 意义 |
---|---|
by |
iteratee(value) ,迭代方法 |
with |
comparator(arrVal, othVal) ,比较方法 |
while |
predicate(value, index, array) ,断言方法 |
last |
fromRight ,指示是否从右向左 |
right |
fromRight ,指示是否从右向左 |
deep |
depth 或CLONE_DEEP_FLAG ,指示是否深度运算 |
这里面大部分的后缀还是很容易看明白它的作用的,但是迭代方法 by
和比较方法 with
就很难分明白。多分析了几个方法,把自己的理解分享下。
就拿 uniq
方法举例,同样都是去重,uniqBy
和 uniqWith
的官方示例如下:
// uniqBy的官方示例
uniqBy([2.1, 1.2, 2.3], Math.floor);
// => [2.1, 1.2]
// uniqWith的官方示例
const objects = [
{ x: 1, y: 2 },
{ x: 2, y: 1 },
{ x: 1, y: 2 },
];
uniqWith(objects, isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
很显然,uniqBy
的示例中,是把数组中所有的元素都向下取整后进行了对应的去重,也就是说挨个比较了 Math.floor(2.1)
、Math.floor(1.2)
、Math.floor(2.3)
,相同
的就对应去重.
而在 uniqWith
中,是调用了 isEqual
进行的两两比较,也就是说挨个比较 isEqual(objects[0], objects[1])
、isEqual(objects[0], objects[2])
、isEqual(objects[1], objects[2])
,返回true
的就对应去重。
所以在我看来,with
是可以完全实现所有的 by
的,比如 uniqBy
的官方示例可以使用 uniqWith
来实现。
// uniqBy的官方示例
uniqBy([2.1, 1.2, 2.3], Math.floor);
// => [2.1, 1.2]
// 用uniqWith实现
uniqWith(
[2.1, 1.2, 2.3],
(arrVal, othVal) => Math.floor(arrVal) === Math.floor(othVal)
);
// => [2.1, 1.2]
uniq 和 union 家族
将 uniq
和 union
家族放在一起分析,是因为 union
的实现是利用的先将多个数组展平,然后再去重来实现的,所以 union
家族的三个方法都依赖到了 baseUniq
。