_.differenceBy(array, [values], [iteratee=_.identity])
与_.difference相比,它多接收一个iteratee参数。暂且称之为迭代器。web
_.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
更像是一个结果集。 ide
为什么提早调用。在最终的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里,有以下的code
_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); // => [{ 'x': 2 }]
这里的iteratee
,传入的是一个字符串x
,咱们大概知道它是什么什么意思,比对,对象的x
的值。对象
咱们能够推想,对于iteratee
,咱们会根据它不一样的类型包装成不一样的函数,lodash
中相关代码以下element
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); }
显然是以下的几种解决字符串
identity
,返回第一个参数。
function identity(value) { return value; }
property
,返回属性的值。
它的做用是
* var objects = [ * { 'a': { 'b': 2 } }, * { 'a': { 'b': 1 } } * ]; * * _.map(objects, _.property('a.b')); * // => [2, 1]
建立一个返回给定对象的 path 的值的函数。
这些又能够总结开一章'lodash中的迭代器',咱们稍后再写。