JavaScript实用库:Lodash源码数组函数解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable

本章的内容主要是:first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable


在这里插入图片描述

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

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


1、_.first -> _.head(array)

根据lodash中文文档介绍,通过该方法可以获取到数组的第一个元素

可以看到啊,它有两个名词:firsthead

我们来看它的例子:
在这里插入图片描述

例子也很通俗易懂啊,这里我就不多说了

接下来看源码:

function head(array) {
  //数组不为空则输出数组第一个元素
  return (array && array.length) ? array[0] : undefined;
}

module.exports = head;

还好,源码很简单


2、_.flatten(array)

根据中文文档介绍:减少一级array嵌套深度

看到这个我们就立马想起了扁平化数组核心函数:baseFlatten,可能源码中都是基于它来实现的

下面直接来看例子啊
在这里插入图片描述
就一个例子,还挺容易懂的,发现在数组内部少了一个嵌套

那么这是怎么来实现的呢?下面看源码:

function flatten(array) {
  //获取数组的长度
  var length = array == null ? 0 : array.length;
  //数组长度为0输出空数组
  //不为0则使用baseFlatten函数向下扁平化1层
  return length ? baseFlatten(array, 1) : [];
}

module.exports = flatten;

源码不多,果然是基于baseFlatten来实现的
有了这个核心函数还是很容易实现这个功能的


3、_.flattenDeep(array)

根据中文文档介绍,该方法能够将数组化为一维数组,也就是说无论嵌套多少层都能化为一维数组

下面我们来看例子:
在这里插入图片描述
也是一个简简单单的例子,希望源码也那么简单

下面我们来看源码:

/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0;

/**
 * Recursively flattens `array`.
 *
 * @static
 * @memberOf _
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to flatten.
 * @returns {Array} Returns the new flattened array.
 * @example
 *
 * _.flattenDeep([1, [2, [3, [4]], 5]]);
 * // => [1, 2, 3, 4, 5]
 */
function flattenDeep(array) {
  var length = array == null ? 0 : array.length;
  return length ? baseFlatten(array, INFINITY) : [];
}

module.exports = flattenDeep;

它的实现与flatten明明一模一样,为什么能够化为一维数组呢,因为我们定义的变量INFINITY的值是 1 / 0,这个值位于baseFlatten函数的第二个参数位时意味着展开层数无限,所以能化为一维数组啦


4、_.flattenDepth(array, [depth=1])

这个方法和前面两个差不多,但是该方法的第二个参数是能够指定层级的,默认为0,当第二个值没有时,该方法就和flatten是一样的了

我们接下来看例子;
在这里插入图片描述
这个我也不多说了,还是挺容易理解的

接下来我们看源码是怎么实现的:

function flattenDepth(array, depth) {
  //获取数组长度
  var length = array == null ? 0 : array.length;
  //数组长度为0则输出空数组
  if (!length) {
    return [];
  }
  //确定depth的值
  //当depth的值没有定义时,赋值为1
  //当有定义时赋值传入值的整数值
  depth = depth === undefined ? 1 : toInteger(depth);
  //扁平化数组
  return baseFlatten(array, depth);
}

module.exports = flattenDepth;

该方法还是基于baseFlatten的扁平化方法
既然这样,我觉得有必要再提及一次这个核心函数


5、baseFlatten

因为中文文档没有介绍,所以我们只能直接看源码了

/**
 * The base implementation of `flatten` with support for restricting flattening.
 *
 * @private
 * @param {Array} array The array to flatten.
 * @param {number} depth The maximum recursion depth.
 * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
 * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
 * @param {Array} [result=[]] The initial result value.
 * @returns {Array} Returns the new flattened array.
 */
//这个方法用于数组展开
//array需要展开操作的数组,depth需要展开的层数
//predicate用于判断值是否可展开
//isStrict标识用于判断是否约束值必须通过predicate方法的检查
function baseFlatten(array, depth, predicate, isStrict, result) {
  predicate || (predicate = isFlattenable)//predicate每次循环都会调用,用来判断当前值是否是一个可展开的array-like对象
  result || (result = [])

  if (array == null) {//需要展开的数组是空,就返回空数组
    return result
  }

  for (const value of array) {
    if (depth > 0 && predicate(value)) {//如果展开层数大于0且当前循环值可展开
      if (depth > 1) {//如果展开层数大于一层就继续递归调用,层数减一
        // Recursively flatten arrays (susceptible to call stack limits).
        baseFlatten(value, depth - 1, predicate, isStrict, result)
      } else {//如果只展开一层,就展开后push到result里
        result.push(...value)
      }
    } else if (!isStrict) {//如果没有传递isStrict标识,就直接将当前循环值push入结果数组
      result[result.length] = value
    }
  }
  return result
}

export default baseFlatten

实现过程还是稍微比较复杂的

既然到了这里,还有一个函数我觉得也可以一并说一下:isFlattenable


6、isFlattenable

很遗憾,文档里面也没有介绍
该方法的功能是:检查一个变量是否是一个可展开的对象或者数组

接下来我们看源码:

/** Built-in value reference. */
const spreadableSymbol = Symbol.isConcatSpreadable

/**
 * Checks if `value` is a flattenable `arguments` object or array.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
 */
function isFlattenable(value) {
  return Array.isArray(value) || isArguments(value) ||
    !!(spreadableSymbol && value && value[spreadableSymbol])
    //如果是数组,则可展开
    //如果是arguments对象,则可展开
    //如果当前环境含有Symbol对象,且此变量含有Symbol.isConcatSpreadable属性,Symbol.isConcatSpreadable用于改变array或者array-like对象使用concat时的默认行为
}

export default isFlattenable

如果可展开则输出true,反之false


今天就到这里了,明天继续

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章