differenceBy
用法
_.differenceBy(array, [values], [iteratee=_.identity])
功能
与_.difference相比,它多接收一个iteratee参数。暂且称之为迭代器。
demo
_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
源码
上两篇已经涉及过相关的代码,仍是在baseDifference
function baseDifference(array, values, iteratee, comparator) {
var index = -1,
includes = arrayIncludes,//方法。
isCommon = true,
length = array.length,
result = [],
valuesLength = values.length;
if (!length) {
return result;
}
if (iteratee) { // 迭代器函数。
values = arrayMap(values, baseUnary(iteratee)); // 这里提前处理下 while循环里边有个判段,这里提前就遍历,处理数据。
}
if (comparator) { //comparator存在,includes从arrayIncludes =》arrayIncludesWith,
includes = arrayIncludesWith;
isCommon = false;
}
else if (values.length >= LARGE_ARRAY_SIZE) {
//- 大型数组的优化,这里默认理解为超过200就是大数组。大的数组启用缓存。
includes = cacheHas; // includes方法设置为cacheHas处理,这里也是做缓存
isCommon = false;//标示 不是普通方式处理了
values = new SetCache(values);
}
outer:
//切记,比对的是array,values
while (++index < length) {
var value = array[index],//array的一个element
computed = iteratee ? iteratee(value) : value;//如果有迭代器,就处理成为computed
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) { // 取出来的数据不是NaN
var valuesIndex = values.length;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer; //跳会outer,继续执行 因为是求差集,也就是value中的元素,在array不能存在。 这里有相同,array中的当前元素就不应该在结果集里出现。
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
需要注意的代码片段
if (iteratee) { // 迭代器函数。
values = arrayMap(values, baseUnary(iteratee)); //
}
便于思考,此时的differenceBy
传入了三个参数array,values,iteratee
,在当前代码片段已经通过arrayMap(values, baseUnary(iteratee))
,已经遍历使用iteratee
,返回的values
更像是一个结果集。
为何提前调用。在最终的while
循环中,还要遍历array
,调用iteratee
进行比对。显然内层仍然需要一个遍历,但是我们不希望每个遍历再去调用一次迭代器。在外层一次处理,开销远远每次在其中调用。
筛选出结果的部分,
while (++index < length) {
var value = array[index],//array的一个element
computed = iteratee ? iteratee(value) : value;//如果有迭代器,就处理成为computed
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) { // 取出来的数据不是NaN
var valuesIndex = values.length;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer; //跳会outer,继续执行 因为是求差集,也就是value中的元素,在array不能存在。 这里有相同,array中的当前元素就不应该在结果集里出现。
}
}
result.push(value);
}
//不会执行下边的逻辑。
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
这不是结束的好时候
写到这,在官网提供的demo里,有如下的
_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
// => [{ 'x': 2 }]
这里的iteratee
,传入的是一个字符串x
,我们大概知道它是什么什么意思,比对,对象的x
的值。
我们可以推想,对于iteratee
,我们会根据它不同的类型包装成不同的函数,lodash
中相关代码如下
baseIteratee(iteratee, 2)
function baseIteratee(value) {
// Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
// See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
if (typeof value == 'function') {
return value;
}
if (value == null) {
return identity;
}
if (typeof value == 'object') {
return isArray(value)
? baseMatchesProperty(value[0], value[1])
: baseMatches(value);
}
return property(value);
}
显然是如下的几种解决
- value如果是函数,直接返回
- 如果是null,返回identity
- 如果是Object 又会根据是否是数组,返回不同的。
- 以上都不属于,直接返回property(value)
identity
,返回第一个参数。
function identity(value) {
return value;
}
property
,返回属性的值。
它的作用是
* var objects = [
* { 'a': { 'b': 2 } },
* { 'a': { 'b': 1 } }
* ];
*
* _.map(objects, _.property('a.b'));
* // => [2, 1]
创建一个返回给定对象的 path 的值的函数。
这些又可以总结开一章'lodash中的迭代器',我们稍后再写。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。