difference方法
功能
创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中。
使用方法
_.difference([3, 2, 1], [4, 2]);
// => [3, 1]
源码分析
var difference = baseRest(function(array, values) {
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
: [];
});
该方法用到了baseReset
方法。它接收的参数是一个匿名函数,匿名函数内接收两个参数,一个是array数组
,另一个就是defference的两个参数
/**
* The base implementation of `_.rest` which doesn't validate or coerce arguments.
* _.reset的基本实现,但是不会校验或者corce参数。
* @private
* @param {Function} func The function to apply a rest parameter to.
* @param {number} [start=func.length-1] The start position of the rest parameter.
* @returns {Function} Returns the new function.
*/
function baseRest(func, start) { // start = undefined
start = nativeMax(start === undefined ? (func.length - 1) : start, 0); // var nativeMax = Math.max;
return function() {
var args = arguments,
index = -1,
length = nativeMax(args.length - start, 0),
array = Array(length);
while (++index < length) {
array[index] = args[start + index];
}
index = -1;
var otherArgs = Array(start + 1);
while (++index < start) {
otherArgs[index] = args[index];
}
otherArgs[start] = array;
return apply(func, this, otherArgs);
};
}
baseReset
是_.rest
方法(创建一个函数,调用func时,this绑定到创建的新函数,并且start之后的参数作为数组传入。)的基础实现。
看一下它执行的效果。
var say = _.rest(function(what, names) {
return what + ' ' + _.initial(names).join(', ') +
(_.size(names) > 1 ? ', & ' : '') + _.last(names);
});
say('hello', 'fred', 'barney', 'pebbles');
// => 'hello fred, barney, & pebbles'
_.rest
,传入一个匿名函数,返回一个新函数,并赋值给了say
,say('hello', 'fred', 'barney', 'pebbles')
,其中hello
对应的是what
,剩余的参数对应的是names
。
再回到baseReset
.
- step1 start这里,如果没传入start则start就是0
- step2 baseReset执行后,返回了一个函数,由于闭包,又保证了func,和start的访问。
(往上看好烦啊,我copy了返回的函数到下边)
// func函数 ,start=0
return function() { // arguments 就像上文say函数调用时传入的参数,假设此时传入了6个参数,[a,b,c,d,e,f]
var args = arguments,//args.length = 6
index = -1,
length = nativeMax(args.length - start, 0),//6
array = Array(length);// array为长度为6的数组,
while (++index < length) { // 0,1,2,3,4,5 <6
array[index] = args[start + index]; // arr[0] = args[0+0],arr[1]= args[0+1]
}
// finally 6个长度的数组`array` array = [a,b,c,d,e,f]
index = -1; // 重置index = -1
var otherArgs = Array(start + 1); // otherArgs 为一个长度的数组 [] length = 1
while (++index < start) {
otherArgs[index] = args[index];// otherArgs = 取出args[0]
}
otherArgs[start] = array;// otherArgs[0] = [a,b,c,d,e,f]
return apply(func, this, otherArgs); // apply执行
};
此处apply
比原生的apply速度更快,作用跟原生js的apply用法和作用是一样的。
function apply(func, thisArg, args) {
switch (args.length) {
case 0: return func.call(thisArg);
case 1: return func.call(thisArg, args[0]);
case 2: return func.call(thisArg, args[0], args[1]);
case 3: return func.call(thisArg, args[0], args[1], args[2]);
}
return func.apply(thisArg, args);
}
注意: while中的i++和 ++i的区别,++i是先算值再判断符合条件,i++则是先判断是否符合条件,再自增。
difference
的关键代码就是这段.
baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
接下来自然要看baseDifference
,baseFlatten
.
baseFlatten
在concat一篇中
已经出现过了,是用来打平多维数组。
接下俩看baseDifference
**
* -.difference的基本实现。
*
* @private
* @param {Array} array The array to inspect. 需要被检查的数组
* @param {Array} values The values to exclude. 需要被排除出去的数组
* @param {Function} [iteratee] The iteratee invoked per element. 迭代器函数,调用每个element
* @param {Function} [comparator] The comparator invoked per element. 比较器,也会调用每个ele
* @returns {Array} Returns the new array of filtered values. 返回被过滤调的新的数组
*/
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) { // 迭代器函数。 这里需要研究arrayMap 和baseUnary方法了
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 = valuesLength;
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;
}
普通的处理方式相对好处理一些。isCommon
用来标示是否使用普通处理。为了做优化,作者显然做了更多。有两种情况需要做优化
- comparator函数传入,此时
incluedes=arrayIncludesWith
- values数组太大。此时
incluedes=cacheHas
,`values = new SetCache(values);
else if (!includes(values, computed, comparator)) {
result.push(value);
}
非正常情况下做的处理代码。
这块详细说,代码就太长了再开一篇吧。
相关方法分析
arrayIncludes
/**
* 数组中Array是否包含 value ,
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludes(array, value) {
var length = array ? array.length : 0;
return !!length && baseIndexOf(array, value, 0) > -1;
}
// arrayIncludes(["123"],"123") => true
baseIndexOf
/**
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
* _.indexOf的基本实现,没有fromIndex的边界检查
* @private
* @param {Array} array The array to inspect. 被检查的数组
* @param {*} value The value to search for. 被查找的值
* @param {number} fromIndex The index to search from. 从哪个位置开始search
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseIndexOf(array, value, fromIndex) {
if (value !== value) { //NaN就调用baseFindIndex
return baseFindIndex(array, baseIsNaN, fromIndex);
}
var index = fromIndex - 1, // -1
length = array.length; //
while (++index < length) {
if (array[index] === value) {
return index; //遍历判断结果,有符合条件 返回index,否则为-1
}
}
return -1;
}
arrayMap
/**
* A specialized version of `_.map` for arrays without support for iteratee
* shorthands.
*
* @private
* @param {Array} [array] The array to iterate over. 用来被遍历的数组
* @param {Function} iteratee The function invoked per iteration. 迭代器
* @returns {Array} Returns the new mapped array.
*/
function arrayMap(array, iteratee) {
var index = -1,
length = array ? array.length : 0,
result = Array(length); //结果数组
while (++index < length) {
result[index] = iteratee(array[index], index, array); // 这里就遍历了数据,返回遍历的结果。
}
return result;
}
baseUnary
/**
* 创建一个最多接受一个参数的函数,忽略多余的参数。
*
* @private
* @param {Function} func The function to cap arguments for.
* @returns {Function} Returns the new capped function.
*/
function baseUnary(func) {
return function(value) {
return func(value);
};
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。