从重复到优雅:前端筛选逻辑的优化之旅

引言:重复代码的困境

在前端开发中,数据筛选是一个高频需求。当面对类似 filterNameA、filterNameB、filterNameC 等多字段筛选时,许多开发者会本能地写出重复的条件分支。这虽然功能可行,却隐藏着维护性差、可读性低、性能隐患等问题。

本文将通过一个真实案例,展示如何通过策略模式、函数式编程和逻辑抽象,将冗余代码转化为简洁高效的解决方案。

优化前的代码

js 复制代码
// ...

for (const i in filterParams) {
  if (filterParams[i] !== undefined) {
    if (i === 'filterNameA') {
      listData = listData.filter(item =>
        filterParams[i].includes(item?.filterNameA || '')
      )
    }
    if (i === 'filterNameB') {
      listData = listData.filter(item =>
        filterParams[i].includes(item?.filterNameB || '')
      )
    }
    if (i === 'filterNameC') {
      listData = listData.filter(item =>
        filterParams[i].includes(item?.filterNameC || '')
      )
    }
    if (i === 'filterNameD') {
      listData = listData.filter(item =>
        filterParams[i].includes(item?.filterNameD || '') || item?.items?.find(child => filterParams[i].includes(child?.filterNameD || ''))
      )
    }
    if (i === 'filterNameE') {
      listData = listData.filter(item =>
        filterParams[i].includes(item?.filterNameE || '')
      )
    }
  }
}
// ...

原始代码的三大痛点

  1. 重复劳动:每个字段的 if 分支几乎相同,仅字段名不同
  2. 硬编码耦合:字段名直接写入逻辑,修改需求时必须改动核心代码
  3. 性能损耗:链式 filter 导致多次遍历数据,时间复杂度 O(n*m)

优化四部曲

  1. 策略模式解耦
js 复制代码
const fieldFilters = { fieldName: (item, value) => /* 过滤逻辑 */ }

将每个字段的过滤逻辑封装为独立函数,消除重复分支。

  1. 单次遍历优化

使用Object.entries + every组合,在一次遍历中完成所有条件判断:

js 复制代码
list.filter(item => Object.entries(filterParams).every(([key, value]) => /*...*/) )
  1. 防御性编程

空值合并运算符 ?? 统一处理 undefined/null

可选链 ?. 避免深层属性访问报错

  1. 特殊逻辑封装

对于 filterNameD 等复杂场景,独立函数保持主逻辑简洁:

js 复制代码
const childMatch = item?.items?.some(child => /*...*/)

优化后的代码

js 复制代码
/**
 * 表头筛选选项
 * @param {Array} listData 表格源数据
 * @param {Object} filterParams 已选择表头筛选项
 * @returns {Array} 筛选后的表格源数据
 */
export function filterListData(listData, filterParams) {
  if (!filterParams || !listData) {
    return listData
  }

  // 定义字段映射和过滤逻辑
  const fieldFilters = {
    filterNameA: (item, value) => value?.includes(item?.filterNameA ?? ''),
    filterNameB: (item, value) => value?.includes(item?.filterNameB ?? ''),
    filterNameC: (item, value) => value?.includes(item?.filterNameC ?? ''),
    filterNameD: (item, value) => {
      // 检查主项或子项中是否包含指定的筛选值
      const mainItemMatch = value?.includes(item?.filterNameD)
      const childItemMatch =
        item?.items?.length &&
        item.items.some(child => value?.includes(child.filterNameD))
      return mainItemMatch || childItemMatch
    },
    filterNameE: (item, value) => value?.includes(item?.filterNameE ?? ''),
  }

  return listData.filter(item => {
    // 检查所有筛选条件
    return Object.entries(filterParams).every(([key, value]) => {
      // 如果值为 undefined 或 空字符串 或 为空数组,跳过该筛选条件
      if (
        value === undefined ||
        value === null ||
        value === '' ||
        (Array.isArray(value) && value.length === 0)
      ) {
        return true
      }

      const filterFn = fieldFilters[key]
      return filterFn ? filterFn(item, value) : true
    })
  })
}

优化效果对比

指标 优化前 优化后
时间复杂度 O(n*m) O(n)
可扩展性 需修改主逻辑 仅增删映射表

延伸思考

  • 动态配置:将 fieldFilters 提取为参数,支持运行时注册新过滤规则
  • 性能监控:对大数据集添加 console.time 量化优化收益
  • 单元测试:每个过滤函数应具备独立测试用例

结语:优雅代码的哲学

最好的代码不是能运行的代码,而是像散文一样可读、像数学一样精确、像乐高一样可组合的代码。本次优化不仅减少了 80%的重复代码,更构建了一个易于维护的过滤框架------这正是前端工程化的魅力所在。

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏

相关推荐
不爱吃糖的程序媛2 小时前
Electron 智能文件分析器开发实战适配鸿蒙
前端·javascript·electron
Doro再努力2 小时前
2025_11_14洛谷【入门1】数据结构刷题小结
前端·数据结构·算法
UWA3 小时前
Gears 实测室:第六期・《黑色沙漠》手游如何精准决策性能优化
性能优化·游戏开发·uwa·游戏测试
IT_陈寒3 小时前
SpringBoot 3.2新特性实战:这5个隐藏技巧让你的应用性能飙升50%
前端·人工智能·后端
flashlight_hi3 小时前
LeetCode 分类刷题:3217. 从链表中移除在数组中存在的节点
javascript·数据结构·leetcode·链表
Java追光着3 小时前
React Native 自建 JS Bundle OTA 更新系统:从零到一的完整实现与踩坑记录
javascript·react native·react.js
努力往上爬de蜗牛3 小时前
react native 运行问题和调试 --持续更新
javascript·react native·react.js
eason_fan3 小时前
Monorepo性能噩梦:一行配置解决VSCode卡顿与TS类型崩溃
前端·typescript·visual studio code
天天进步20154 小时前
Webpack到Vite:构建工具迁移实战经验总结
前端·webpack·node.js
0***144 小时前
免费的WebAssembly模块打包,Webpack配置
前端·webpack·wasm