JS-手写 Array.pototype.flat

1,103 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

前言

flat()  方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

本文记叙手动实现的基本思路和代码。

基本思路

思路其实不复杂,很简单,就是遍历数组:

  1. 如果子元素也是数组,那么根据扁平化深度的需求,确定是否继续遍历子元素,展开扁平化;
  2. 如子元素不是数组,直接返回子元素本身即可。

但是因为 flat 扁平化数组后,不会改变子元素展开后位置,如:

flat([1, [2, 3], 4])
// [1, 2, 3, 4]

所以使用递归的方式来实现比较简单明了,如果使用循环和栈等非递归方式实现,会比较麻烦,需要使用变量缓存的信息数据比较多。

代码

首先,定义函数,函数接受两个参数:

    1. 需要被扁平化的数组 array;
    1. 扁平化的深度 depth; 还必须返回新的数组,所以定义的代码如下:
/**
 * 手写 flat 函数 递归实现
 * @param { Array<any> } array 需要被扁平化的数组
 * @param { number } depth 扁平化深度,默认为1
 * @returns { Array<any> }
 */
function myFlat_recursion (array: Array<any>, depth = 1): Array<any> {
  // 返回结果的数组
  const returnArray = []

  return returnArray
}

接着,对参数进行检测,检测的条件有三个:

    1. array 必须为数组
    1. depth 必须为 number
    1. depth 必须大于等于 0 代码如下:
  /**
   * 参数检测,如果参数错误,返回 `array` 本身,以下参数条件
   * 1. array 必须为数组
   * 2. depth 必须为 number
   * 3. depth 必须大于等于 0 
   */
  if (!Array.isArray(array) || typeof depth !== 'number' || depth < 0) {
    return array
  }

然后就是遍历 array ,出现以下几种情况:

    1. depth - 1 如果大于等于 0,并且子元素 item 是数组,则递归调用 myFlat_recursion ,把子元素和 depth - 1 作为参数入参,把返回结果放入当前的返回数组中;
    1. 其他情况直接将子元素 item 放入当前的返回数组中。 代码如下:
  // 返回结果的数组
  const returnArray = []
  // 递归调用时的扁平化深度
  const newDepth = depth - 1

  for (let i = 0, len = array.length; i < len; i++) {
    const item = array[i]
    // 判断,确定 returnArray.push 时的值
    Array.isArray(item) && newDepth >= 0 ? returnArray.push(...myFlat_recursion(item, newDepth)) : returnArray.push(item)
  }

完整代码如下:

function myFlat_recursion (array: Array<any>, depth = 1): Array<any> {
  if (!Array.isArray(array) || typeof depth !== 'number' || depth < 0) {
    return array
  }

  const returnArray = []
  const newDepth = depth - 1

  for (let i = 0, len = array.length; i < len; i++) {
    const item = array[i]
    Array.isArray(item) && newDepth >= 0 ? returnArray.push(...myFlat_recursion(item, newDepth)) : returnArray.push(item)
  }

  return returnArray
}

测试一把:

const arr = [1, [2, 3, [4, 5, [12, 3, "zs"], 7, [8, 9, [10, 11, [1, 2, [3, 4]]]]]]]

const depth = Number.MAX_SAFE_INTEGER

console.log('Array.prototype.flat:', arr.flat(depth))

console.log('my flat recursion:', myFlat_recursion(arr, depth))

微信截图_20221027163604.png

如果 const depth = 2,结果如下:

微信截图_20221027163700.png