将lodash中比较常用且原生写法比较复杂的,或是官方文档(中文版)中描述不是很易懂的方法记录下来。
数组篇
// 原数组
let a = [1, 2, 3, 4, 5, 4, 3, 2, 1]
dropWhile & dropRightWhile
官方的描述和例子都让人很疑惑,不如方法名实在——左过滤和右过滤
参数:
1、原数组
2、过滤条件
_.dropWhile(a, (v) => v < 3)
// return [3, 4, 5, 4, 3, 2, 1]
_.dropRightWhile(a, (v) => v < 3)
// return [1, 2, 3, 4, 5, 4, 3]
该方法是有break的,实用价值应该不大。
difference
实为filter三连
- difference(array, [filter])
直接判断是否与过滤数组中的元素相等
_.difference(a, [2, 3])
// [1, 4, 5, 4, 1]
- differenceBy(array, [filter], iteratee)
比较前用iteratee包装,再比较是否相等
_.differenceBy(a, [1.1, 2.1], Math.floor)
// return [3, 4, 5, 4, 3]
这里a中的元素也会用Math.floor处理一遍,不过原数组都是整数,所以看不出来
- differenceWith(array, [filter], comparator)
与differenceBy不同,这个更贴近于difference,comparator接收原数组和过滤数组的元素,比较进行返回,也就是不限制只能等于。
_.differenceWith(a, [2.1, 4.1], (v1, v2) => v1 > v2)
// [1, 2, 2, 1]
v1是原数组元素,v2是过滤数组元素,这里应该是个嵌套循环,每个a.ele都需要满足comparator返回false才能不被过滤,比如3,只满足3 > 4.1为false,不满足3 > 2.1为false,所以被过滤了。
注:这里可以看出来lodash函数的命名风格,后面也有类似的——funName是原功能,funNameBy是(用iteratee)包装元素,funNameWith是自定义比较规则,一般用于比较对象数组。
总结:实用性来看,difference会比较有用,其他情况下(对象数组的复杂过滤)我更可能想到的是原生实现。
flatten
对比原生的flat:
_.flatten(a) == a.flat()
_.flattenDeep(a) == _flattenDepth(a, Infinity) == a.flat(Infinity)
_flattenDepth(a, n) == a.flat(n)
所以用flat还少打点字,且压平数组的使用场景,目前还没见过。
pull
删除方法,所有相关方法均会改变原数组
- pull
_.pull(a, 3, 4)
// [1, 2, 5, 2, 1]
要删除的元素依次用,隔开
- without
参数规则同pull,但是不会改变原数组
_.without(a, 3, 4)
// [1, 2, 5, 2, 1]
// a [1, 2, 3, 4, 5, 4, 3, 2, 1]
- pullAll
_.pullAll(a, [3, 4])
// [1, 2, 5, 2, 1]
要删除的元素是一个数组,与call & apply类似。
pullAllBy与pullAllWith与前者同。
- pullAt
_.pullAt(a, 0, 2)
// return [1, 3]
// 原数组变为 [2, 4, 5, 4, 3, 2, 1]
与前面还是有点区别,参数是删除的元素索引,返回的是删除的元素。
- remove
_.remove(a, v => v & 1)
// return [1, 3, 5, 3, 1]
// 原数组变为 [2, 4, 4, 2]
同xxxWith,参数是比较规则,这里规则是奇数;同pullAt,返回值是删除的元素,原数组会变。
pull系列实用价值很不错,用起来相比于原生实现会简短很多。
take
按关联性来说,应该放到drop后面,即过滤的反面,笔记顺序按照官网列的来。
本系列所有方法均不改变原数组。
- take(arr, n = 1)
相当于a.slice(0, n)
_.take(a)
// [1]
_.take(a, 3)
// [1, 2, 3]
- takeRight(arr, n = 1)
相当于a.slice(-n)
_.take(a)
// [1]
_.take(a, 3)
// [3, 2, 1]
- takeWhile & takeRightWhile(arr, callback)
当cb返回true时take,返回false时break。 - tail(a)
即slice(1),不同于shift,这个不改变原数组。
总结:slice的封装版,可能用惯了slice还不太习惯用这些。
union
之前有个求交集的,intersection,没记录,感觉用处不大,这个是用来求并集且去重的。
- union([arrs])
参数无限制长度。
_.union([1,2,5], [1,2,2,4])
// [1, 2, 5, 4]
有By和With,不赘述。
uniq
- uniq(arr)
去重,同[...new Set(arr)]
_.uniq(a)
// [1, 2, 3, 4, 5]
有By和With,不赘述。
zip
- zip([arrs])
不太好描述,有点像矩阵翻转。
_.zip(['fred', 'barney'], [30, 40], [true, false])
// [['fred', 30, true], ['barney', 40, false]]
_.zip(['fred', 'barney'], [30, 40, 50], [true, false, true, false])
// [["fred", 30, true], ["barney", 40, false], [undefined, 50, true], [undefined, undefined, false]]
如果出现分组的数组长度不一致的情况,以最长的长度为结果数组的长度,分配元素arrN[i],没有自然是undefined。
- unzip([arrs])
与zip相反的作用
_.unzip([['sv', 1, 'kk'], ['bs', 2, 'ss'], []])
// [["sv", "bs", undefined], [1, 2, undefined], ["kk", "ss", undefined]]
- zipObject(arr1, arr2)
这种日常开发很常见,一个是Object.keys,一个是Object.values,这个方法是重组object。
_.zipObject(['a', 'b'], [1, 2])
// {a: 1, b: 2}
_.zipObject(['a', 'b'], [1, 2, 3])
// {a: 1, b: 2}
_.zipObject(['a', 'b', 'c', 'd'], [1, 2, 3])
// {a: 1, b: 2, c: 3, d: undefined}
结果对象按keyArr.length算,如果keyArr.length < valArr.length,多的值舍去,反之则值用undefined填补。
- zipObjectDeep(arr1, arr2)
加了深度的重组object,这种情况不常见,遇到了我应该也会自己遍历。
_.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2])
// { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
- zipWith([arrs], iteratee)
with类作用都一样,这里列举一种可能的使用场景。
_.zipWith(['Joe', 'John'], [22, 25], [8000, 10000], function(a, b, c, d) {
return `My name is ${a}, ${b} years old, salary: ¥${c}.`;
});
// ["My name is Joe, 22 years old, salary: ¥8000.", "My name is John, 25 years old, salary: ¥10000."]
当某类的实例属性被分组时,可以这样重组使用。
- unzipWith([[arrs]], iteratee)
类似zipWith,区别只在于参数1用数组包起来了,类比apply,call。
注:如果没有iteratee,unzipWith == upzip,zip同理。
_.unzipWith([[1, 10, 100], [2, 20, 200]], _.add)
// [3, 30, 300]
_.zipWith([1, 10, 100], [2, 20, 200], _.add)
// [3, 30, 300]
总结:感觉上zipObject和zipWith会比较有用,其他的用处不大。
xor
symmetric difference,对查等分,指由所有只在两个集合其中之一的元素组成的集合。也就是:先求全集,再剔除交集。
_.xor([1, 2, 3], [1, 2, 4])
// [3, 4]
_.xor([1, 2, 3, 3], [1, 2, 4, 5])
// [3, 4, 5]
// 结果是去重的
有By和With方法。实用性不高。
集合篇
看起来还是数组,collection不知道还包含其他什么类型,Set不行。
countBy(col, iteratee)
类似count+groupBy。
_.countBy([1, 2, 1])
// {1: 2, 2: 1}
_.countBy([1.1, 2.3, 1.4], Math.floor)
// {1: 2, 2: 1}
_.countBy(['one', 'two', 'three'], 'length')
// {3: 2, 5: 1}
这里总结一下单属性作为iteratee
// propName == (ele) => ele[propName]
网友评论