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

相关推荐
To_OC4 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
To_OC5 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn5 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
এ慕ོ冬℘゜6 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
随心点儿7 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
kyriewen8 小时前
我让AI改一个bug——它偷偷动了5个我没让它碰的地方
前端·javascript·ai编程
gis开发之家13 小时前
《Vue3 从入门到大神35篇》Vue3 源码详解(五):effect 依赖收集原理——track 与 trigger 是如何工作的?
javascript·typescript·前端框架·vue3·vue3源码
橘子星14 小时前
我一个前端切图仔,凭什么能在浏览器里跑大模型?
前端·javascript·前端框架
半个落月14 小时前
用 LangChain JS 做可控写作实验:理解温度参数、提示词与异步调用
javascript·人工智能·后端
观远数据14 小时前
Excel到数据资产池:文件数据入湖的治理规范怎么建
前端·javascript·excel