今日分享:
每一步都是曼妙的风景~
_.difference(array, [values])
使用:
创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中。(注:即创建一个新数组,这个数组中的值,为第一个数字(array 参数)排除了给定数组中的值。)该方法使用SameValueZero做相等比较。结果值的顺序是由第一个数组中的顺序确定。
使用示例:
.difference([3, 2, 1], [4, 2]);
// => [3, 1]
尝试手写:
①返回新数组;②查重;③只查第一个数组相对别的数据是否有重复,不会合并之后再去重。
let dif_arr1 = [3,2,1],dif_arr2 = [4,2];
function my_difference(arr1, arr2) {
let newArr = [];
for(var i = 0 ; i < arr1.length; i++) {
if(arr2.indexOf(arr1[i]) === -1) {
newArr.push(arr1[i])
}
}
return newArr;
}
console.log(my_difference(dif_arr1,dif_arr2)); // [3, 1]
源码方案:
var difference = baseRest(function(array, values) {
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
: [];
});
// 补充函数解释 ①baseRest
function baseRest(func, start) {
return setToString(overRest(func, start, identity), func + '');
}
// 补充函数解释 ②isArrayLikeObject
function isArrayLikeObject(value) {
return isObjectLike(value) && isArrayLike(value);
}
/**
* baseFlatten函数:将数组扁平化
**/
// ③ 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));
}
// 为每个元素调用的比较器, 支持比较关系不限于等于; 存在比较器,isCommon修改为false,否则为true默认进行查重
if (comparator) {
includes = arrayIncludesWith;
isCommon = false;
}
// 数目较大时使用set查找
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas;
isCommon = false;
values = new SetCache(values);
}
// 这个地方 outer 的用法不太懂,打个※。后面继续学习后补充
outer:
while (++index < length) {
var value = array[index],
// 存在迭代器,对目标元素进行迭代后返回,否则赋值value
computed = iteratee == null ? value : iteratee(value);
value = (comparator || value !== 0) ? value : 0;
// 根据传入的比较器进行比较
// 常规查重。computed === computed 只有值为NaN的情况为false
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
// 根据比较器进行查重 includes 为之前赋值的比较器
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
类似方法
.differenceBy(array, [values], [iteratee=.identity])
它接受一个 iteratee (注:迭代器), 调用array 和 values 中的每个元素以产生比较的标准。 结果值是从第一数组中选择。iteratee 会调用一个参数:(value)。(注:首先使用迭代器分别迭代array 和 values中的每个元素,返回的值作为比较值)。
使用示例:
_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
// => [3.1, 1.3]
// The `_.property` iteratee shorthand.
_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
// => [{ 'x': 2 }]
源码
var differenceBy = baseRest(function(array, values) {
var iteratee = last(values);
if (isArrayLikeObject(iteratee)) {
iteratee = undefined;
}
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), baseIteratee(iteratee, 2))
: [];
});
_.differenceWith(array, [values], [comparator])
它接受一个 comparator (注:比较器),它调用比较array,values中的元素。 结果值是从第一数组中选择。comparator 调用参数有两个:(arrVal, othVal)。
使用示例:
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
_.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
// => [{ 'x': 2, 'y': 1 }]
源码:
var differenceWith = baseRest(function(array, values) {
var comparator = last(values);
if (isArrayLikeObject(comparator)) {
comparator = undefined;
}
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
: [];
});
对比
可以看到,三个方法调用的核心方法是一致的,通过传参不同返回不同结果。核心源码支持查重、计算后查重、自定义比较条件。