js设计模式-装饰器模式

一.概念

装饰器模式核心价值:

  1. 非侵入式扩展:无需修改核心功能源代码
  2. 责任链模式:通过装饰器链组合复杂逻辑
  3. 避免条件判断:消除冗余的if (featureX)代码膨胀

二.使用举例

  1. 原型扩展
javascript 复制代码
<html>
<button tag="login" id="button">点击打开登录浮层</button>
<script>
  Function.prototype.after = function (afterfn) {
    var __self = this;
    return function () {
      var ret = __self.apply(this, arguments);
      afterfn.apply(this, arguments);
      return ret;
    }
  };
  var showLogin = function () {
    console.log('打开登录浮层');
  }
  var log = function () {
    console.log('上报标签为: ' + this.getAttribute('tag'));
  }
  showLogin = showLogin.after(log); // 打开登录浮层之后上报数据
  document.getElementById('button').onclick = showLogin; 
</script>

</html>
  1. 工具函数扩展
javascript 复制代码
<html>
  <button tag="login" id="button">点击打开登录浮层</button>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // 工具函数:创建函数执行后的增强函数
      function composeAfter(original, afterFn) {
        return function(...args) {
          const result = original.apply(this, args);
          afterFn.apply(this, args);
          return result
        };
      }

      // 原始函数:不包含副作用
      const showLogin = () => {
        console.log('打开登录浮层');
      };

       // 副作用函数:需要访问触发元素属性
      const trackEvent = function() {
        console.log('上报标签为: ' + this.getAttribute('tag'));
      };

      // 函数组合:合并核心逻辑与监视记录
      const combinedFunction = composeAfter(showLogin, trackEvent);

      // DOM 交互封装在闭包内
      const button = document.getElementById('button');
      button.addEventListener('click', combinedFunction);
    });
  </script>
</html>

三. 应用场景

  1. 日志记录
    实现对函数调用的跟踪,不改动原函数逻辑
javascript 复制代码
function logDecorator(func) {
  return function (...args) {
    console.log(`Calling ${func.name} with ${args}`);
    const result = func.apply(this, args);
    console.log(`Result: ${result}`);
    return result;
  };
}

// 使用装饰器
const add = logDecorator(function(a, b) {
  return a + b;
});

add(2, 3); // 输出调用日志
  1. 性能分析
    测量函数执行时间
javascript 复制代码
function timerDecorator(func) {
  return function (...args) {
    const start = performance.now();
    const result = func.apply(this, args);
    console.log(`Time taken: ${performance.now() - start}ms`);
    return result;
  };
}

// 装饰计算密集型函数
const fibonacci = timerDecorator(function(n) {
  return n <= 1 ? n : fibonacci(n-1) + fibonacci(n-2);
});

fibonacci(30); // 输出耗时

3.参数校验

确保函数参数符合规范

javascript 复制代码
function validateParams(func) {
  return function (...args) {
    args.forEach(arg => {
      if (typeof arg !== 'number') throw new Error('Invalid parameter type');
    });
    return func.apply(this, args);
  };
}

const multiply = validateParams(function(a, b) {
  return a * b;
});

multiply(2, 'three'); // 抛出参数类型错误

关键优势总结:

  1. 代码复用:将常用功能封装为装饰器库
  2. 高内聚性:避免将横切逻辑嵌入核心业务代码
  3. 可插拔性:通过装饰器叠加或替换灵活控制功能组合
  4. DRY原则:如权限验证逻辑只需维护一处

通过装饰器模式,开发者能更自然地实现"开闭原则":对扩展开放,对修改关闭。

四. 总结

通过装饰器模式,框架开发者能够:

  1. 保持核心功能的最小稳定
  2. 提供无限扩展可能性
  3. 减少因功能增加导致的维护成本指数级增长

这种将「必须功能」与「期望功能」分离的设计,在现代前端框架(如React Hooks)、中间件(如Koa)中得到了广泛采用,是构建可扩展系统的核心策略

相关推荐
今年下半年12 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
可乐鸡翅yeah_14 小时前
hls.js 切换多个视频源,新手开发常见踩坑
开发语言·前端·javascript·ios·ffmpeg·音视频·safari
kyriewen14 小时前
我实测了前端日期的 5 个坑:差 8 小时只是开始
前端·javascript·程序员
anew___14 小时前
《从零手写操作系统 (11):文件系统初探——initrd与VFS抽象层》
java·javascript·算法
今年下半年15 小时前
【VUE3】移动端:使用腾讯地图显示区域统计与放大显示资产点位
javascript·前端框架·vue·地图
a努力。15 小时前
LangChain Agent消息链路全解析
java·前端·javascript
今年下半年15 小时前
【前端】ant-design-vue 表格「行、列都动态」的处理方案
前端·javascript·vue.js
默_笙16 小时前
🚕 缺料就出门买:给 RAG 装上"信息够不够"的判断力
前端·javascript
志尊宝17 小时前
Vue3 零基础每日笔记(054):Pinia 三件套详解——state / getters / actions 全搞懂
前端·javascript·vue.js·vue·前端开发
wangyadong31717 小时前
# el-table 复选框无法选中问题记录
前端·javascript·vue.js