前端开发中过度封装的现象与思考

文摘   2024-09-19 10:12   上海  

前言

作为公司内的一名高级前端码喽,大大小小也封装过了不少组件和功能,我逐渐意识到封装并非全是优点,也会存在一些不可忽视的潜在劣势。

在项目中,我们急切地对各种功能和 UI 进行封装,却在不经意间忽略了封装可能带来的额外成本与潜在问题。比如,在之前的一个项目中,为了实现一个看似简单的列表展示功能,我将数据获取、渲染逻辑以及交互处理都塞进了一个繁杂的组件中。后续当需要对列表的某一特定功能进行细微调整时,由于封装的过度复杂,修改工作变得极为棘手,耗费了大量时间去梳理内部的逻辑关系。

还有一次我在对一个表单验证功能的封装时,为追求过高的通用性,添加了过多的配置选项和繁杂的验证规则。这不但增加了代码量,还使得新加入团队的成员在使用时感到困惑,理解和运用这个封装的成本大幅提高。如果让我在写标准代码和学习过度封装的组件之间做选择,我绝对毫不犹豫的选择写标准代码。

一、前端功能封装的优势

  1. 可以提高代码复用性 在众多项目中,常碰到类似的数据请求、表单验证等功能需求。将这些功能封装成独立的函数或模块,能极大提升代码的复用程度。例如,我们成功封装了一个通用的数据获取函数,在不同页面中仅需传入各异的参数,就能顺利获取所需数据,无需反复编写请求逻辑。

  2. 有效增强代码的可维护性 封装后的功能代码相对独立,当需要对功能进行修改或优化时,只需在封装的模块内操作,不会对其他使用该功能的部分产生任何影响。如此一来,代码的维护工作变得更加清晰、易于掌控。

  3. 大幅提升代码的可读性 通过为封装的功能赋予清晰、有意义的函数名和详尽的参数说明,其他开发者能够迅速理解其功能和使用方式,这样也极大提高团队协作的效率。写到这里我突然想起曾经在一个屎山项目中看到过的aaaa、Areyouok、jiashizheng等变量和函数名,我花了好久的时间才把它们修改正常...

二、前端功能封装的劣势

  1. 事极必反

    有时为追求极致的封装效果,可能会对一些简单且复用频率不高的功能进行封装,这反倒会增加代码的复杂程度和理解成本。例如,一个仅仅用于计算两个数之和的简单功能,若过度封装,可能会令后续的开发者感到迷茫。

    代码示例:

    function add(a, b{
      return a + b;
    }

    // 过度封装
    function complexAdd(a, b{
      if (typeof a!== 'number' || typeof b!== 'number') {
        throw new Error('输入必须为数字');
      }
      const result = a + b;
      // 一些额外的复杂逻辑
      return result;
    }

    在一个小型项目中,仅仅为了计算两个数字的和,使用了复杂的封装函数complexAdd,导致新同事在理解和使用时花费了过多时间,而原本简单的add函数就能满足需求。

  2. 可能隐藏底层实现细节

    过度封装或许会让使用功能的开发者对其内部实现一无所知。当问题出现时,可能需要耗费更多时间去理解封装内部的逻辑,进而影响问题的排查和解决效率。

三、UI 二次封装的优势

  1. 成功统一风格和交互

    在大型项目中,保障 UI 的一致性至关重要。通过对基础 UI 组件进行二次封装,能够明确统一的样式、交互行为和响应式规则。例如,对按钮组件进行二次封装,设定不同状态下的颜色、尺寸和点击效果。

  2. 显著提高开发效率

    开发人员能够直接运用封装好的 UI 组件,迅速搭建页面,无需在样式和交互的调整上耗费大量时间。

  3. 方便后期维护和更新

    当需要对 UI 进行整体风格的调整或优化时,只需修改封装的组件,所有使用该组件的页面都会自动更新,大幅减少了维护的工作量。

四、UI 二次封装的劣势

  1. 过度封装的危害

    代码示例:

    // 过度封装的输入框组件
    class OverlyComplexInput extends React.Component {
      constructor(props) {
        super(props);
        this.state = { value'' };
      }

      handleChange = (e) => {
        // 复杂的处理逻辑
        this.setState({ value: e.target.value });
        // 更多的额外操作
      }

      render() {
        return (
          <input 
            value={this.state.value} 
            onChange={this.handleChange} 
            // 过多的样式和属性设置
          />

        );
      }
    }

    在一个性能要求较高的页面中,使用了过度封装的输入框组件,导致页面加载缓慢,用户输入时出现明显的卡顿。

  • 增加不必要的代码量和复杂度,致使应用的加载性能降低。例如,一个简单的输入框组件,如果过度封装了很多复杂的逻辑和样式,可能会使代码体积过大。
  • 可能引入过多的抽象层次,让代码变得难以理解和调试。复杂的封装结构可能让开发者在排查 UI 问题时感到无从下手。
  • 过度复杂的封装在频繁的渲染和更新操作中,可能会导致性能瓶颈,影响用户体验。
  • 灵活性受限 过于严格的封装可能限制了开发者在特定场景下对 UI 进行个性化定制的能力。有时候,某些页面可能需要独特的样式或交互效果,而过度封装的组件无法满足这些特殊需求。

  • 版本兼容性问题 当对封装的 UI 组件进行更新时,可能会与之前使用该组件的页面产生兼容性问题。新的版本可能改变了组件的行为、样式或接口,导致使用旧版本组件的页面出现显示异常或功能失效。

  • 所以在实际的开发过程中,我们需要权衡封装带来的好处和潜在的问题。封装应该是有针对性的,基于实际的复用需求和项目的规模。同时,要保持封装的适度性,避免过度封装带来的负面影响。只有这样,才能真正提高前端开发的效率和质量。


    原文:https://juejin.cn/post/7387731346733121551

    web前端进阶
    坚持原创,分享前端技术文章。
     最新文章