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)中得到了广泛采用,是构建可扩展系统的核心策略

相关推荐
ZC跨境爬虫1 小时前
跟着 MDN 学JavaScript day_9:字符串方法实战挑战与解题思路
开发语言·前端·javascript
hewins1 小时前
NestJS 从入门到精通
javascript
柒和远方1 小时前
LeetCode 452. 用最少数量的箭引爆气球 —— 区间贪心经典:排序 + 扫描一箭穿心
javascript·python·算法
小小龙学IT2 小时前
Drizzle ORM:TypeScript 生态中冉冉升起的数据库工具链引言
javascript·数据库·typescript
旺王雪饼 www3 小时前
localStorage 和 sessionStorage区别与联系
服务器·前端·javascript
এ慕ོ冬℘゜3 小时前
【双月日期范围选择器】博客(可直接交作业 / 上线)
前端·javascript·交互·jquery
VidDown3 小时前
VidDown 使用介绍:一个免费、本地化的在线工具集
javascript·编辑器·音视频·视频编解码·视频
小牛itbull4 小时前
告别传统主题开发!ReactPress Theme Starter —— 用 Next.js 15 构建现代化无头博客
javascript·cms·react·wordpress·nextjs·reactpress·blog-theme
深蓝电商API4 小时前
逆向工程入门:从Chrome DevTools到JS混淆还原
前端·javascript·chrome·爬虫·chrome devtools
nap-joker4 小时前
使用n8n+飞书搭建自动推送新闻机器人
javascript·json·飞书·工作流·n8n·36氪新闻向客户端推送