如何手写一个JS函数实现数组深度不限的扁平化处理?

2026-03-31 17:191阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2626个文字,预计阅读时间需要11分钟。

如何手写一个JS函数实现数组深度不限的扁平化处理?

目录+前言+主题实现+扁平化方法+封装+flatten

1.ES6 flat

2.toString

3.正则替换

4.循环递归

4.1 循环+concat+push 4.2 增加参数控制扁平化深度 4.3 巧用 reduce 4.4 使用 Generator 函数

5.使用扁平化

目录
  • 前言
  • 题目实现扁平化的方法 封装 flatten
  • 1. ES6 flat
  • 2. toString
  • 3. 使用正则替换
  • 4. 循环递归
    • 4.1 循环 + concat + push
    • 4.2 增加参数控制扁平化深度
    • 4.3 巧用 reduce
    • 4.4 使用 Generator 函数
  • 5. 使用堆栈 stack 避免递归
    • 6.while 循环+ some方法

      前言

      由于上半年参加了校招的技术面试, 前前后后面了20多个人了, 每次面试都会让应聘者手写一下数组扁平化flat(),但是发现居然没有一个能够完成写出来, 所以打算总结一下如果遇到了数组扁平化的题目(也可以叫做手动封装flat()方法),到底应该怎么写,怎么写可以得更高的分;

      话不多说, 接下来我将站在面试官的角度分析所有常见的实现方法, 并附上对应的得分情况: 五星打分制

      满分: ⭐⭐⭐⭐⭐

      题目实现扁平化的方法 封装 flatten

      题目描述:

      已有多级嵌套数组 : [1, [2, [3, [4, 5]]], 6] 将其扁平化处理 输出: [1,2,3,4,5,6]

      什么是扁平化

      定义 : 扁平化就是将多维数组变成一维数组,不存在数组的嵌套

      1. ES6 flat

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

      参数:

      depth(可选) 指定要提取嵌套数组的结构深度,默认值为 1

      返回值:

      返回一个新数组,包含数组与提取嵌套数组的所有元素的新数组

      使用 Infinity,可展开任意深度的嵌套数组

      封装思路: 使用 es6 自带 API 处理

      const arr = [1, [2, [3, [4, 5]]], 6] function flatten(params) { return params.flat(Infinity) } console.log(flatten(arr)); // 输出: [1,2,3,4,5,6]

      得分 :

      直接使用自带的方法可以很快的实现, 但是面试官当然不希望就看到这些呀 !

      2. toString

      如果数组的项全为数字,可以使用join(),toString()可以利用数组toString() 转为字符串

      function flatten(arr) { return arr.toString().split(',').map(item =>parseFloat(item)) } console.log(flatten(arr)); // 输出:[ 1, 2, 3, 4, 5, 6 ]

      得分 : ⭐ (并不是要考你的数组的方法调用)

      3. 使用正则替换

      看到嵌套的数组,如果在字符串的角度上看就是多了很多[],如果把它们替换就可以实现简单的扁平化

      function flatten (arr) { console.log('JSON.stringify(arr)', typeof JSON.stringify(arr)) let str= JSON.stringify(arr).replace(/(\[|\])/g, ''); str = '[' + str + ']'; arr = JSON.parse(str); return arr } console.log(flatten(arr))

      得分 : ⭐ (并不是要考你的数组的方法调用)

      4. 循环递归

      4.1 循环 + concat + push

      当只有一层嵌套数组使用push的方式扁平化

      [1, [2, 3,4,5,6]]

      let result = []; for (let i = 0; i < arr2.length; i++) { result = result.concat((arr2[i])); } console.log(result); [ 1, 2, 3, 4, 5, 6 ]

      如果有多层嵌套的数组就需要使用 递归的思想 :

      思路

      • 循环判断数组的每一项是否是数组: Array.isArray(arr[i])
      • 是数组就递归调用上面的扁平化一层的代码 result = result.concat(flatten(arr[i]));
      • 不是数组,直接通过push添加到返回值数组

      function flatten(arr) { let result = []; for (let i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])); } else { result.push(arr[i]) } } return result } console.log(flatten(arr));

      或者使用forEach 立即执行函数

      // 递归版本的反嵌套 function flatten(array) { var flattend = []; (function flat(array) { array.forEach(function(el) { if (Array.isArray(el)) flat(el); else flattend.push(el); }); })(array); return flattend; }

      当然循环可以更改成forEach循环,for of ...等其他循环,简单的循环递归就能够一样的解决啦~

      得分: ⭐⭐⭐ (能够使用递归写出数组扁平化,缺少控制层级关系)

      4.2 增加参数控制扁平化深度

      这个可以理解为手写flat()方法啦~

      // forEach 遍历数组会自动跳过空元素 const eachFlat = (arr = [], depth = 1) => { const result = []; // 缓存递归结果 // 开始递归 (function flat(arr, depth) { // forEach 会自动去除数组空位 arr.forEach((item) => { // 控制递归深度 if (Array.isArray(item) && depth > 0) { // 递归数组 flat(item, depth - 1) } else { // 缓存元素 result.push(item) } }) })(arr, depth) // 返回递归结果 return result; } // for of 循环不能去除数组空位,需要手动去除 const forFlat = (arr = [], depth = 1) => { const result = []; (function flat(arr, depth) { for (let item of arr) { if (Array.isArray(item) && depth > 0) { flat(item, depth - 1) } else { // 去除空元素,添加非 undefined 元素 item !== void 0 && result.push(item); } } })(arr, depth) return result; }

      得分: ⭐⭐⭐⭐ (能够使用递归写出数组扁平化,可以通过参数控制层级关系)

      4.3 巧用 reduce

      reduce 方法为数组中的每个元素按序执行一个reducer函数,每一次运行 reducer 会将先前元素的计算结构作为参数传入,最后将其结果汇总为单个返回值

      参数:

      • callbackFn 一个 reducer 函数,包含四个参数:
      • previousVal :上一次调用callbackFn时的返回值,在第一次调用时,若指定了初始值initialValue,previousVal 的值就位 initialValue,否则初始值就是为数组的索引为 0 的元素
      • currentVal:数组中正在处理的元素,在第一次调用时,若指定了初始值,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
      • currentIndex: 数组中正在处理的元素的索引,若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始
      • array : 用于遍历的数组
      • initialValue(可选) : 作为第一次调用 callback 函数时参数 previousValue 的值

      返回值: 使用 reducer 回调函数遍历整个数组后的结果

      思路:

      当我们使用 reduce 来解析第一层数组,可以得到:

      const arr = [1, [[2, 3], 4],5] const result = arr.reduce((acc, val) => acc.concat(val), []); console.log(result); // 输出: [1,[2,3],4,5]

      可以看出上面的代码可以扁平化一层数组,对于多层级嵌套的数组, 这个时候就需要使用递归的思想来解决问题了,再次遍历数组,发现数组元素任然是数组的时候,再次执行上面扁平化

      手写方法

      const arr = [1, [[2, 3], 4],5] function flatten (arr,deep=1) { return arr.reduce((acc,val) => acc.concat(Array.isArray(val)? flatten(val,deep-1):val),[]) } console.log(arr, Infinity); // 输出:[ 1, 2, 3, 4, 5, 6 ]

      得分: ⭐⭐⭐⭐ (能够使用递归写出数组扁平化,巧用reduce方法可加分)

      4.4 使用 Generator 函数

      GeneratorFunction是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

      它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。

      整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 语句注明。Generator 函数的执行方法如下。

      构造器生成新的生成器函数

      function* flatten(array) { for (const item of array) { if (Array.isArray(item)) { yield* flatten(item); } else { yield item; } } }

      得分: ⭐⭐⭐ (使用Generator 函数 进行递归)

      5. 使用堆栈 stack 避免递归

      递归循环都可通过维护一个堆结构来解决

      如果不使用递归数组来实现扁平化,可以使用堆栈来解决

      深度的控制比较低效,因为需要检查每一个值的深度

      如何手写一个JS函数实现数组深度不限的扁平化处理?

      思路:

      • 把数组通过一个栈来维护
      • 当栈不为空的时候循环执行处理
      • pop()将栈尾出栈
      • 如果出栈的元素是数组,就将该元素解构后每一元素进行入栈操作
      • 出栈的元素不是数组就push进返回值res
      • 反转恢复原数组的顺序

      var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]]; function flatten(arr) { const stack = [...arr]; const res = []; while (stack.length) { // 使用 pop 从 stack 中取出并移除值 const next = stack.pop(); if (Array.isArray(next)) { // 使用 push 送回内层数组中的元素,不会改动原始输入 stack.push(...next); } else { res.push(next); } } // 反转恢复原数组的顺序 return res.reverse(); } flatten(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

      得分: ⭐⭐⭐⭐ (使用数据结构栈的特性取代递归操作,减少时间复杂度)

      6.while 循环+ some方法

      some :方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。

      思路

      通过some来判断数组中是否用数组,通过while不断循环执行判断, 如果是数组的话可以使用 拓展运算符... ... 每次只能展开最外层的数组,加上contact来减少嵌套层数,

      function flatten(arr) { while (arr.some(item=&gt; Array.isArray(item))) { console.log(...arr) arr = [].concat(...arr) console.log(arr) } return arr } console.log(flatten(arr));

      得分: ⭐⭐⭐⭐ (使用while循环取消递归操作, 巧用some操作进行判断)

      以上就是JS前端面试数组扁平化手写flat函数示例的详细内容,更多关于JS数组扁平化flat函数的资料请关注易盾网络其它相关文章!

      本文共计2626个文字,预计阅读时间需要11分钟。

      如何手写一个JS函数实现数组深度不限的扁平化处理?

      目录+前言+主题实现+扁平化方法+封装+flatten

      1.ES6 flat

      2.toString

      3.正则替换

      4.循环递归

      4.1 循环+concat+push 4.2 增加参数控制扁平化深度 4.3 巧用 reduce 4.4 使用 Generator 函数

      5.使用扁平化

      目录
      • 前言
      • 题目实现扁平化的方法 封装 flatten
      • 1. ES6 flat
      • 2. toString
      • 3. 使用正则替换
      • 4. 循环递归
        • 4.1 循环 + concat + push
        • 4.2 增加参数控制扁平化深度
        • 4.3 巧用 reduce
        • 4.4 使用 Generator 函数
      • 5. 使用堆栈 stack 避免递归
        • 6.while 循环+ some方法

          前言

          由于上半年参加了校招的技术面试, 前前后后面了20多个人了, 每次面试都会让应聘者手写一下数组扁平化flat(),但是发现居然没有一个能够完成写出来, 所以打算总结一下如果遇到了数组扁平化的题目(也可以叫做手动封装flat()方法),到底应该怎么写,怎么写可以得更高的分;

          话不多说, 接下来我将站在面试官的角度分析所有常见的实现方法, 并附上对应的得分情况: 五星打分制

          满分: ⭐⭐⭐⭐⭐

          题目实现扁平化的方法 封装 flatten

          题目描述:

          已有多级嵌套数组 : [1, [2, [3, [4, 5]]], 6] 将其扁平化处理 输出: [1,2,3,4,5,6]

          什么是扁平化

          定义 : 扁平化就是将多维数组变成一维数组,不存在数组的嵌套

          1. ES6 flat

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

          参数:

          depth(可选) 指定要提取嵌套数组的结构深度,默认值为 1

          返回值:

          返回一个新数组,包含数组与提取嵌套数组的所有元素的新数组

          使用 Infinity,可展开任意深度的嵌套数组

          封装思路: 使用 es6 自带 API 处理

          const arr = [1, [2, [3, [4, 5]]], 6] function flatten(params) { return params.flat(Infinity) } console.log(flatten(arr)); // 输出: [1,2,3,4,5,6]

          得分 :

          直接使用自带的方法可以很快的实现, 但是面试官当然不希望就看到这些呀 !

          2. toString

          如果数组的项全为数字,可以使用join(),toString()可以利用数组toString() 转为字符串

          function flatten(arr) { return arr.toString().split(',').map(item =&gt;parseFloat(item)) } console.log(flatten(arr)); // 输出:[ 1, 2, 3, 4, 5, 6 ]

          得分 : ⭐ (并不是要考你的数组的方法调用)

          3. 使用正则替换

          看到嵌套的数组,如果在字符串的角度上看就是多了很多[],如果把它们替换就可以实现简单的扁平化

          function flatten (arr) { console.log('JSON.stringify(arr)', typeof JSON.stringify(arr)) let str= JSON.stringify(arr).replace(/(\[|\])/g, ''); str = '[' + str + ']'; arr = JSON.parse(str); return arr } console.log(flatten(arr))

          得分 : ⭐ (并不是要考你的数组的方法调用)

          4. 循环递归

          4.1 循环 + concat + push

          当只有一层嵌套数组使用push的方式扁平化

          [1, [2, 3,4,5,6]]

          let result = []; for (let i = 0; i < arr2.length; i++) { result = result.concat((arr2[i])); } console.log(result); [ 1, 2, 3, 4, 5, 6 ]

          如果有多层嵌套的数组就需要使用 递归的思想 :

          思路

          • 循环判断数组的每一项是否是数组: Array.isArray(arr[i])
          • 是数组就递归调用上面的扁平化一层的代码 result = result.concat(flatten(arr[i]));
          • 不是数组,直接通过push添加到返回值数组

          function flatten(arr) { let result = []; for (let i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])); } else { result.push(arr[i]) } } return result } console.log(flatten(arr));

          或者使用forEach 立即执行函数

          // 递归版本的反嵌套 function flatten(array) { var flattend = []; (function flat(array) { array.forEach(function(el) { if (Array.isArray(el)) flat(el); else flattend.push(el); }); })(array); return flattend; }

          当然循环可以更改成forEach循环,for of ...等其他循环,简单的循环递归就能够一样的解决啦~

          得分: ⭐⭐⭐ (能够使用递归写出数组扁平化,缺少控制层级关系)

          4.2 增加参数控制扁平化深度

          这个可以理解为手写flat()方法啦~

          // forEach 遍历数组会自动跳过空元素 const eachFlat = (arr = [], depth = 1) => { const result = []; // 缓存递归结果 // 开始递归 (function flat(arr, depth) { // forEach 会自动去除数组空位 arr.forEach((item) => { // 控制递归深度 if (Array.isArray(item) && depth > 0) { // 递归数组 flat(item, depth - 1) } else { // 缓存元素 result.push(item) } }) })(arr, depth) // 返回递归结果 return result; } // for of 循环不能去除数组空位,需要手动去除 const forFlat = (arr = [], depth = 1) => { const result = []; (function flat(arr, depth) { for (let item of arr) { if (Array.isArray(item) && depth > 0) { flat(item, depth - 1) } else { // 去除空元素,添加非 undefined 元素 item !== void 0 && result.push(item); } } })(arr, depth) return result; }

          得分: ⭐⭐⭐⭐ (能够使用递归写出数组扁平化,可以通过参数控制层级关系)

          4.3 巧用 reduce

          reduce 方法为数组中的每个元素按序执行一个reducer函数,每一次运行 reducer 会将先前元素的计算结构作为参数传入,最后将其结果汇总为单个返回值

          参数:

          • callbackFn 一个 reducer 函数,包含四个参数:
          • previousVal :上一次调用callbackFn时的返回值,在第一次调用时,若指定了初始值initialValue,previousVal 的值就位 initialValue,否则初始值就是为数组的索引为 0 的元素
          • currentVal:数组中正在处理的元素,在第一次调用时,若指定了初始值,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
          • currentIndex: 数组中正在处理的元素的索引,若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始
          • array : 用于遍历的数组
          • initialValue(可选) : 作为第一次调用 callback 函数时参数 previousValue 的值

          返回值: 使用 reducer 回调函数遍历整个数组后的结果

          思路:

          当我们使用 reduce 来解析第一层数组,可以得到:

          const arr = [1, [[2, 3], 4],5] const result = arr.reduce((acc, val) => acc.concat(val), []); console.log(result); // 输出: [1,[2,3],4,5]

          可以看出上面的代码可以扁平化一层数组,对于多层级嵌套的数组, 这个时候就需要使用递归的思想来解决问题了,再次遍历数组,发现数组元素任然是数组的时候,再次执行上面扁平化

          手写方法

          const arr = [1, [[2, 3], 4],5] function flatten (arr,deep=1) { return arr.reduce((acc,val) => acc.concat(Array.isArray(val)? flatten(val,deep-1):val),[]) } console.log(arr, Infinity); // 输出:[ 1, 2, 3, 4, 5, 6 ]

          得分: ⭐⭐⭐⭐ (能够使用递归写出数组扁平化,巧用reduce方法可加分)

          4.4 使用 Generator 函数

          GeneratorFunction是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

          它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。

          整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 语句注明。Generator 函数的执行方法如下。

          构造器生成新的生成器函数

          function* flatten(array) { for (const item of array) { if (Array.isArray(item)) { yield* flatten(item); } else { yield item; } } }

          得分: ⭐⭐⭐ (使用Generator 函数 进行递归)

          5. 使用堆栈 stack 避免递归

          递归循环都可通过维护一个堆结构来解决

          如果不使用递归数组来实现扁平化,可以使用堆栈来解决

          深度的控制比较低效,因为需要检查每一个值的深度

          如何手写一个JS函数实现数组深度不限的扁平化处理?

          思路:

          • 把数组通过一个栈来维护
          • 当栈不为空的时候循环执行处理
          • pop()将栈尾出栈
          • 如果出栈的元素是数组,就将该元素解构后每一元素进行入栈操作
          • 出栈的元素不是数组就push进返回值res
          • 反转恢复原数组的顺序

          var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]]; function flatten(arr) { const stack = [...arr]; const res = []; while (stack.length) { // 使用 pop 从 stack 中取出并移除值 const next = stack.pop(); if (Array.isArray(next)) { // 使用 push 送回内层数组中的元素,不会改动原始输入 stack.push(...next); } else { res.push(next); } } // 反转恢复原数组的顺序 return res.reverse(); } flatten(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

          得分: ⭐⭐⭐⭐ (使用数据结构栈的特性取代递归操作,减少时间复杂度)

          6.while 循环+ some方法

          some :方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。

          思路

          通过some来判断数组中是否用数组,通过while不断循环执行判断, 如果是数组的话可以使用 拓展运算符... ... 每次只能展开最外层的数组,加上contact来减少嵌套层数,

          function flatten(arr) { while (arr.some(item=&gt; Array.isArray(item))) { console.log(...arr) arr = [].concat(...arr) console.log(arr) } return arr } console.log(flatten(arr));

          得分: ⭐⭐⭐⭐ (使用while循环取消递归操作, 巧用some操作进行判断)

          以上就是JS前端面试数组扁平化手写flat函数示例的详细内容,更多关于JS数组扁平化flat函数的资料请关注易盾网络其它相关文章!