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

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

程序员文章站 2024-01-03 12:59:28
...

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


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

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

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


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

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

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

我们来看它的例子:
JavaScript实用库:Lodash源码数组函数解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable

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

接下来看源码:

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

module.exports = head;

还好,源码很简单


2、_.flatten(array)

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

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

下面直接来看例子啊
JavaScript实用库:Lodash源码数组函数解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable
就一个例子,还挺容易懂的,发现在数组内部少了一个嵌套

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

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)

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

下面我们来看例子:
JavaScript实用库:Lodash源码数组函数解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable
也是一个简简单单的例子,希望源码也那么简单

下面我们来看源码:

/** 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是一样的了

我们接下来看例子;
JavaScript实用库:Lodash源码数组函数解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable
这个我也不多说了,还是挺容易理解的

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

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


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

上一篇:

下一篇: