欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript实用库:Lodash源码数组函数解析(二)

程序员文章站 2024-01-03 11:15:28
...

本章内容主要是:difference、baseDifference、isArrayLikeObject、isArrayLike、baseRest

JavaScript实用库:Lodash源码数组函数解析(二)

Lodash是一个非常好用方便的JavaScript的工具库,使得我们对数据处理能够更加得心应手

接下来我要对Lodash的源码进行剖析学习
每天几个小方法,跟着我一起来学lodash吧

  


1、_.difference(array, [values])

根据中文文档介绍,该函数就是可以将 array中的排除掉[values]中的元素,这是我个人的话语解释,我们来看中文文档解释
JavaScript实用库:Lodash源码数组函数解析(二)

以下是例子:
例子中我们输入了两个数组,第一个数组保持了存在的唯一值
JavaScript实用库:Lodash源码数组函数解析(二)
接下来我们看源码:

/**
 * Creates an array of `array` values not included in the other given arrays
 * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.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 = value
    value = (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 后面用于指定跳转的位置。

作者:就想叫菜鸟
链接:https://www.jianshu.com/p/8946dc5d884e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

没错,这个并非我的解释,我觉得这位作者写得挺好的就引用了一下

  • 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方法取出唯一值


今天虽然只写了一个方法,但是它依赖的方法太多了,一起解释了一遍,今天就这样了,明天继续

上一篇:

下一篇: