递归法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function flatten(arr) {
   function fn(arr, ans = []) {
       if (Array.isArray(arr)) {
           for (const item of arr) {
               if (Array.isArray(item)) {
                   fn(item,ans)
              } else {
                   ans.push(item)
              }
          }
      }
       return ans
  }

   return fn(arr)
}

const array = [1,2,[3,[4,5,[6]]]]
console.log(flatten(array))

继续递归条件: 子项是数组。

终止递归条件:子项不是数组,遍历完成。

迭代法

1
2
3
4
5
6
7
8
9
function flatten(arr) {
   while (arr.some(item => Array.isArray(item))) {
       arr = [].concat(...arr)
  }
   return arr
}

const array = [1,2,[3,[4,5,[6]]]]
console.log(flatten(array))

由于扁平化的核心就是数组子项是否还是数组,这就符合Array.prototype.some()的使用逻辑,且使用[].concat这种字面量的形式也不用像递归法那样开辟新的变量了。

但是面试时如果需要兼容更老的ES版本,比如ES3,还需要手写实现Array.prototype.some()

toString + split 利用JS本身的特性

嵌套数组使用toString后自动转为,分割的字符串,只需要把字符串反向处理回数组即可。

1
2
3
function flatten(arr) {
   return arr.toString().split(',').map(num=>parseInt(num))
}

总结

手写这样的题有递归的方式就会有迭代的方式,面试时还是多想想以迭代法解决,递归比较原始但从笔者自己经验来看经常卡壳,遗忘某一步关键导致递归无法终止。当然,巧妙利用JS自身的某些特性也是不错的解法,但需要对JS的基础掌握得更为扎实。