告别 for 循环嵌套:JavaScript 数组迭代的函数式妙用


传统的 for 循环往往在处理多层数组时,代码变得冗长且难以维护。随着函数式编程思想的普及,JavaScript
提供了一系列强大而优雅的数组方法,可以让我们彻底告别嵌套循环的混乱,使代码更加简洁、可读且易于维护。

嵌套循环的痛点

先看一个典型的嵌套 for 循环示例,假设我们需要从二维数组中筛选出所有偶数并将它们翻倍:

const matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];  
const result = [];  
  
for (let i = 0; i < matrix.length; i++) {  
for (let j = 0; j < matrix[i].length; j++) {  
if (matrix[i][j] % 2 === 0) {  
      result.push(matrix[i][j] * 2);  
    }  
  }  
}  
  
console.log(result); // [4, 8, 12, 16]  

这段代码存在几个问题:

  • 代码冗长,可读性较差
  • 使用中间变量存储状态
  • 循环嵌套越多,代码复杂度指数增长
  • 调试困难,容易出错

函数式方法的优雅替代

1. 扁平化嵌套数组: flat()

flat() 方法可以将嵌套数组扁平化,这样我们就可以对扁平化后的数组进行操作:

2. 映射与过滤: map() filter()

结合 map() filter() 方法,可以轻松实现筛选和转换:

3. 一步到位: flatMap()

对于先扁平化再映射的常见操作, flatMap() 提供了更高效的解决方案:

4. 深层嵌套数组处理

对于更深层次的嵌套,可以指定 flat() 的深度参数,或使用 Infinity 完全展开:

5. 递归与 reduce() 的强大组合

对于更复杂的嵌套结构处理,可以结合 reduce() 和递归实现灵活的解决方案:

functionprocessNestedArrays(arr, processFn) {  
return arr.reduce((result, item) => {  
if (Array.isArray(item)) {  
return [...result, ...processNestedArrays(item, processFn)];  
    }  
  
const processed = processFn(item);  
return processed ? [...result, processed] : result;  
  }, []);  
}  
  
const nestedNumbers = [1, [2, 3], [4, [5, 6, [7, 8]]]];  
const doubledEvens = processNestedArrays(  
  nestedNumbers,  
num => num % 2 === 0 ? num * 2 : null  
);  
  
console.log(doubledEvens); // [4, 8, 12, 16]  

尽管函数式方法在可读性和维护性上有明显优势,但在极端性能要求的场景下,传统循环可能略微高效。然而,现代 JavaScript
引擎对这些高阶函数的优化已经相当出色,对于大多数应用场景,性能差异微乎其微,而代码质量的提升则是显著的。