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

322 阅读1分钟

传统的 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()和递归实现灵活的解决方案:

function processNestedArrays(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 引擎对这些高阶函数的优化已经相当出色,对于大多数应用场景,性能差异微乎其微,而代码质量的提升则是显著的。