数组函数解析(二) difference、baseDifference、isArrayLikeObject、isArrayLike、baseRest"/>
JavaScript实用库:Lodash源码数组函数解析(二) difference、baseDifference、isArrayLikeObject、isArrayLike、baseRest
本章内容主要是:difference、baseDifference、isArrayLikeObject、isArrayLike、baseRest
Lodash是一个非常好用方便的JavaScript的工具库,使得我们对数据处理能够更加得心应手
接下来我要对Lodash的源码进行剖析学习
每天几个小方法,跟着我一起来学lodash吧
1、_.difference(array, [values])
根据中文文档介绍,该函数就是可以将 array中的排除掉[values]中的元素,这是我个人的话语解释,我们来看中文文档解释
以下是例子:
例子中我们输入了两个数组,第一个数组保持了存在的唯一值
接下来我们看源码:
/*** Creates an array of `array` values not included in the other given arrays* using [`SameValueZero`](.0/#sec-samevaluezero)* for equality comparisons. The order and references of result values are* determined by the first array.** **Note:** Unlike `_.pullAll`, this method returns a new array.** @static* @memberOf _* @since 0.1.0* @category Array* @param {Array} array The array to inspect.* @param {...Array} [values] The values to exclude.* @returns {Array} Returns the new array of filtered values.* @see _.without, _.xor* @example** _.difference([2, 1], [2, 3]);* // => [1]*/
var difference = baseRest(function(array, values) {return isArrayLikeObject(array)? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)): [];
});module.exports = difference;
一上来我们就可以看到还使用了其他的很多方法,就像我们昨天的老朋友:扁平化数组 baseFlatten
这里的话 baseFlatten我就不过多介绍了
- baseDifference
/** Used as the size to enable large array optimizations. */
var LARGE_ARRAY_SIZE = 200;/*** The base implementation of methods like `_.difference` without support* for excluding multiple arrays or iteratee shorthands.** @private* @param {Array} array The array to inspect.* @param {Array} values The values to exclude.* @param {Function} [iteratee] The iteratee invoked per element.* @param {Function} [comparator] The comparator invoked per element.* @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;// 判断如果数组的长度是 0,则返回空数组if (!length) {return result;}if (iteratee) {values = arrayMap(values, baseUnary(iteratee));}if (comparator) {includes = arrayIncludesWith;isCommon = false;}// 当数组的长度大于 200 时执行,这是前面给出的常量。else if (values.length >= LARGE_ARRAY_SIZE) {includes = cacheHas;isCommon = false;values = new SetCache(values);}// 标签语法outer:while (++index < length) {var value = array[index],// 当 iteratee == null 时返回 value,否则返回 iteratee(value)computed = iteratee == null ? value : iteratee(value);// 当 comparator 存在或者 value !==0 时,value = valuevalue = (comparator || value !== 0) ? value : 0;if (isCommon && computed === computed) {var valuesIndex = valuesLength;while (valuesIndex--) {if (values[valuesIndex] === computed) {// 如果 values 中有值等于 computed,就退出到最外层的循环,这就是标签语法的作用continue outer;}}result.push(value);}else if (!includes(values, computed, comparator)) {result.push(value);}}return result;
}module.exports = baseDifference;
比如 baseDifference([1, 2], [2, 3, 4]) 这里 array = [1, 2] , values = [2, 3, 4]
初始值 result = [], valuesLength = 3
for 遍历,第一个值 value = 1, computed = 1, valuesIndex = 3;
values[2] = 4 !== value, values[1] = 3 !== value, values[0] = 2 !== value
result = [1]
接下来,遍历第二个值, value = 2, computed = 2, vlauesIndex = 3;
values[2] = 4 !== value, values[1] = 3 !== value, values[0] = 2 == value
当存在值相等的时候,直接跳转到最外层,所以 result = [1]
最后也就是说baseDifference([1, 2], [2, 3, 4]) = [1];
看到 outer:是不是一下子懵了,这就是标签语法,形式是 label: statement,这里的标签可以是除了保留字以外的任意标识符,当然语句也可以是任意语句。它有什么用呢?这个标签就相当于一个定位符,在 break, continue 后面用于指定跳转的位置。
作者:就想叫菜鸟
链接:
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
没错,这个并非我的解释,我觉得这位作者写得挺好的就引用了一下
- isArrayLikeObject
/*** This method is like `_.isArrayLike` except that it also checks if `value`* is an object.** @static* @memberOf _* @since 4.0.0* @category Lang* @param {*} value The value to check.* @returns {boolean} Returns `true` if `value` is an array-like object,* else `false`.* @example** _.isArrayLikeObject([1, 2, 3]);* // => true** _.isArrayLikeObject(document.body.children);* // => true** _.isArrayLikeObject('abc');* // => false** _.isArrayLikeObject(_.noop);* // => false*/
function isArrayLikeObject(value) {return isObjectLike(value) && isArrayLike(value);
}module.exports = isArrayLikeObject;
里面又有一个isArrayLike的方法
- isArrayLike
/*** Checks if `value` is array-like. A value is considered array-like if it's* not a function and has a `value.length` that's an integer greater than or* equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.** @static* @memberOf _* @since 4.0.0* @category Lang* @param {*} value The value to check.* @returns {boolean} Returns `true` if `value` is array-like, else `false`.* @example** _.isArrayLike([1, 2, 3]);* // => true** _.isArrayLike(document.body.children);* // => true** _.isArrayLike('abc');* // => true** _.isArrayLike(_.noop);* // => false*/
function isArrayLike(value) {return value != null && isLength(value.length) && !isFunction(value);
}module.exports = isArrayLike;
isArrayLike方法比较简单,你会发现里面蹦出来个 isLength方法,这个我在这里不过多介绍,是用来判断数据长度是否是一个有限长度
所以总的来说 isArrayLikeObject是判断我们输入的数据是不是一个数组或类数组结构,是则返回true,反之false
- baseRest
/*** The base implementation of `_.rest` which doesn't validate or coerce arguments.** @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) {return setToString(overRest(func, start, identity), func + '');
}module.exports = baseRest;
这个函数主要是对剩余参数的处理,它不用验证参数或者强制输入参数,这个我不过多解释,大家理解就好
那么搞了这么久,我们终于可以解释 difference方法发执行过程了,首先就是传出参数并进行 baseRest剩余参数处理,让后就是直接输出,我们首先判断array是不是数组,如果不是则返回空数组,如果是则进行下一步,将我们的 [values]通过 baseFlatten方法一级扁平化处理,最后通过 baseDifference方法取出唯一值
今天虽然只写了一个方法,但是它依赖的方法太多了,一起解释了一遍,今天就这样了,明天继续
更多推荐
JavaScript实用库:Lodash源码数组函数解析(二) difference、baseDifference、isArrayLikeObject、isAr
发布评论