JS数组专题1️⃣_番外篇 ➖ lodash中的flatten

专题一已经给大家介绍了数组扁平化,本篇将给大家介绍 lodash 中的 flatten 是如何实现的。

一、lodash源码

1.基础函数

  • isFlattenable.js
// isFlattenable.js
import isArguments from '../isArguments.js' // 检查 value 是否是一个类 arguments 对象,在本篇不予讲解。

// ES6中内置属性,可用于判断数组是否可展开. 具体可见 MDN
const spreadableSymbol = Symbol.isConcatSpreadable;
/*
value[Symbol.isConcatSpreadable] === true时可展开,
可手动设置为false value[Symbol.isConcatSpreadable] = false
*/

/**
 * 检查值是否可展开.
 *
 * @private
 * @param {*} value 要检查的值.
 * @returns {boolean} 返回布尔值,可展开 -> true, 不可展开 -> false.
 */
function isFlattenable(value) {
  return Array.isArray(value) || isArguments(value) ||
    !!(spreadableSymbol && value && value[spreadableSymbol]);
}

export default isFlattenable;
复制代码
  • baseFlatten.js
// baseFlatten.js
import isFlattenable from './isFlattenable.js' // 是否可以扁平化

/**
 * _.flatten 的基本实现与支持限制扁平化。
 *
 * @private
 * @param {Array} array 需要扁平化的数组.
 * @param {number} depth 扁平化的深度.
 * @param {boolean} [predicate=isFlattenable] 该函数每次迭代判断是否可展开操作.
 * @param {boolean} [isStrict] 是否可通过 predicate 检查.
 * @param {Array} [result=[]] 初始结果数组.
 * @returns {Array} 返回新的扁平数组.
 */
function baseFlatten(array, depth, predicate, isStrict, result) {
  predicate || (predicate = isFlattenable);
  result || (result = []);

  if (array == null) {
    return result; // 如果数组为空,则直接返回初始化结果
  }

  for (const value of array) {
    if (depth > 0 && predicate(value)) { // 判断深度和是否可展开
      if (depth > 1) {
        // 如果深度大于1,继续递归扁平化数组.
        baseFlatten(value, depth - 1, predicate, isStrict, result);
      } else {
        // 否则 push 进结果集中
        result.push(...value);
      }
    } else if (!isStrict) {
      // 如果不检查数组,直接不展开放进结果集中
      result[result.length] = value;
    }
  }
  return result;
}

export default baseFlatten;
复制代码
  • map.js
/**
 * 通过 iteratee 操作的每个元素,创建一个新数组.
 * iteratee 有三个参数 (value, index, array).
 *
 * @since 5.0.0
 * @category Array
 * @param {Array} array 要操作的数组.
 * @param {Function} iteratee 操作函数.
 * @returns {Array} 返回新的数组.
 * @example
 *
 * function square(n) {
 *   return n * n
 * }
 *
 * map([4, 8], square)
 * // => [16, 64]
 */
function map(array, iteratee) {
  let index = -1;
  const length = array == null ? 0 : array.length;
  const result = new Array(length);

  while (++index < length) {
    result[index] = iteratee(array[index], index, array);
  }
  return result;
}

export default map;
复制代码

2.运用函数

实际上所有的 flatten 都是依赖上面的基础函数。

  • flatten.js
// flatten.js
import baseFlatten from './.internal/baseFlatten.js'

/**
 * 扁平化一级数组.
 *
 * @since 0.1.0
 * @category Array
 * @param {Array} array 将扁平化的数组.
 * @returns {Array} 返回扁平化后的数组.
 * @see flatMap, flatMapDeep, flatMapDepth, flattenDeep, flattenDepth
 * @example
 *
 * flatten([1, [2, [3, [4]], 5]])
 * // => [1, 2, [3, [4]], 5]
 */
function flatten(array) {
  const length = array == null ? 0 : array.length;
  return length ? baseFlatten(array, 1) : [];
}

export default flatten;
复制代码
  • flattenDeep.js
// flattenDeep.js
import baseFlatten from './.internal/baseFlatten.js'

/** 使用一个无限大的数值. */
const INFINITY = 1 / 0

/**
 * 递归最终扁平为只有一级的数组.
 *
 * @since 3.0.0
 * @category Array
 * @param {Array} array 将扁平化的数组.
 * @returns {Array} 返回扁平化后的数组.
 * @see flatMap, flatMapDeep, flatMapDepth, flatten, flattenDepth
 * @example
 *
 * flattenDeep([1, [2, [3, [4]], 5]])
 * // => [1, 2, 3, 4, 5]
 */
function flattenDeep(array) {
  const length = array == null ? 0 : array.length;
  return length ? baseFlatten(array, INFINITY) : [];
}

export default flattenDeep;
复制代码
  • flattenDepth.js
// flattenDepth.js
import baseFlatten from './.internal/baseFlatten.js'

/**
 * 递归将数组扁平化至指定深度.
 *
 * @since 4.4.0
 * @category Array
 * @param {Array} array 将扁平化的数组.
 * @param {number} [depth=1] 最大扁平化深度.
 * @returns {Array} 返回扁平化后的数组.
 * @see flatMap, flatMapDeep, flatMapDepth, flattenDeep
 * @example
 *
 * const array = [1, [2, [3, [4]], 5]]
 *
 * flattenDepth(array, 1)
 * // => [1, 2, [3, [4]], 5]
 *
 * flattenDepth(array, 2)
 * // => [1, 2, 3, [4], 5]
 */
function flattenDepth(array, depth) {
  const length = array == null ? 0 : array.length;
  if (!length) {
    return [];
  }
  depth = depth === undefined ? 1 : +depth; // 没有depth参数时为1,有的时候转化为正数.
  return baseFlatten(array, depth);
}

export default flattenDepth;
复制代码
  • flatMap.js
import baseFlatten from './.internal/baseFlatten.js'
import map from './map.js' // 封装map函数

/**
 * 使用 map 重新创建数组,然后使用 baseFlatten 扁平化一级.
 *
 * @since 4.0.0
 * @category Collection
 * @param {Array|Object} collection 将处理的数组.
 * @param {Function} iteratee 数组遍历处理函数
 * @returns {Array} 返回新的扁平化后的数组.
 * @see flatMapDeep, flatMapDepth, flatten, flattenDeep, flattenDepth, map, mapKeys, mapValues
 * @example
 *
 * function duplicate(n) {
 *   return [n, n]
 * }
 *
 * flatMap([1, 2], duplicate)
 * // => [1, 1, 2, 2]
 */
function flatMap(collection, iteratee) {
  return baseFlatten(map(collection, iteratee), 1);
}

export default flatMap;
复制代码
  • flatMapDeep.js

flattenDeep.js 类似,只不过扁平化之前和 flatMap.js 一样先 map 一遍数组,然后进行扁平化处理。

  • flatMapDepth.js

flattenDepth.js 类似,只不过扁平化之前和 flatMap.js 一样先 map 一遍数组,然后进行扁平化处理。

二、数组原生函数

1.Array.prototype.flat

  • 本函数和 flattenDepth 类似,只不过是多了一个删除空项的功能,挂载在 Array 实例下的函数。
// 判断是否可展开
function isFlattenable(value) {
  const spreadableSymbol = Symbol.isConcatSpreadable;
  return Array.isArray(value) || _.isArguments(value) ||
    !!(spreadableSymbol && value && value[spreadableSymbol]);
}

// 判断空
function isEmpty(value) {
  if (value === undefined || value === null) {
    return true;
  }
  return false;
}

function baseFlatten(array, depth, predicate, isStrict, result) {
  predicate || (predicate = isFlattenable);
  result || (result = []);

  if (array == null) {
    return result; // 如果数组为空,则直接返回初始化结果
  }

  for (const value of array) {
    if (depth > 0 && predicate(value)) { // 判断深度和是否可展开
      if (depth > 1) {
        // 如果深度大于1,继续递归扁平化数组.
        baseFlatten(value, depth - 1, predicate, isStrict, result);
      } else {
        // 否则 push 进结果集中
        result.push(...value);
      }
    } else if (!isStrict && !isEmpty(value)) {
      // 如果不检查数组并且不为空,直接不展开放进结果集中
      result[result.length] = value;
    }
  }
  return result;
}

/**
 * 递归将数组扁平化至指定深度.
 *
 * @param {number} [depth=1] 最大扁平化深度.
 * @returns {Array} 返回扁平化后的数组.
 * @example
 *
 * const array = [1, [2, [3, [4]], 5]]
 *
 * array.flat(1)
 * // => [1, 2, [3, [4]], 5]
 *
 * array.flat(2)
 * // => [1, 2, 3, [4], 5]
 */
Array.prototype.flat = function flattenDepth(depth) {
  const array = this;
  const length = array.length;
  if (!length) {
    return [];
  }
  depth = depth === undefined ? 1 : +depth; // 没有depth参数时为1,有的时候转化为正数.
  return baseFlatten(array, depth);
}
复制代码

转载于:https://juejin.im/post/5b718ab7518825612a2279f6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值