TypeScript装饰器:从入门到精通

news2025/5/17 23:34:57

TypeScript装饰器:从入门到精通

什么是装饰器?

装饰器(Decorator)是TypeScript中一个非常酷的特性,它允许我们在不修改原有代码的情况下,给类、方法、属性等添加额外的功能。想象一下装饰器就像给你的代码"穿衣服",可以一层层地叠加功能,而不会破坏原有的结构。

在ES2016中,装饰器还只是一个提案,但TypeScript已经提前实现了这个功能。要使用装饰器,需要在tsconfig.json中开启experimentalDecorators选项。

装饰器基础

类装饰器

类装饰器是最简单的一种装饰器,它接收一个构造函数作为参数。让我们看个例子:

function logClass(target: Function) {
  console.log(`${target.name} 被装饰了`);
}

@logClass
class MyClass {
  constructor() {
    console.log('创建MyClass实例');
  }
}

const myClass = new MyClass();
// 输出:
// 类 MyClass 被装饰了
// 创建MyClass实例

方法装饰器

方法装饰器可以拦截方法的调用,非常适合用于日志记录、权限验证等场景:

function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  
  descriptor.value = function(...args: any[]) {
    console.log(`调用方法 ${propertyKey},参数: ${JSON.stringify(args)}`);
    const result = originalMethod.apply(this, args);
    console.log(`方法 ${propertyKey} 返回: ${result}`);
    return result;
  };
  
  return descriptor;
}

class Calculator {
  @logMethod
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3);
// 输出:
// 调用方法 add,参数: [2,3]
// 方法 add 返回: 5

装饰器工厂

有时候我们希望装饰器能接收参数,这时候就需要使用装饰器工厂:

function logWithPrefix(prefix: string) {
  return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = function(...args: any[]) {
      console.log(`[${prefix}] 调用方法 ${propertyKey}`);
      return originalMethod.apply(this, args);
    };
    
    return descriptor;
  };
}

class Logger {
  @logWithPrefix('DEBUG')
  log(message: string) {
    console.log(message);
  }
}

const logger = new Logger();
logger.log('这是一条日志');
// 输出:
// [DEBUG] 调用方法 log
// 这是一条日志

装饰器的执行顺序

当多个装饰器应用于同一个声明时,它们的执行顺序很重要:

  1. 参数装饰器,然后是方法、访问器或属性装饰器
  2. 装饰器从最靠近声明的装饰器开始执行
  3. 类装饰器最后执行
function first() {
  console.log('first() 工厂函数');
  return function(target: any) {
    console.log('first() 装饰器');
  };
}

function second() {
  console.log('second() 工厂函数');
  return function(target: any) {
    console.log('second() 装饰器');
  };
}

@first()
@second()
class ExampleClass {}

// 输出:
// first() 工厂函数
// second() 工厂函数
// second() 装饰器
// first() 装饰器

装饰器的实际应用

1. 自动绑定this

在React类组件中,我们经常需要绑定方法的this指向,装饰器可以帮我们自动完成:

function autobind(_: any, _2: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  const adjDescriptor: PropertyDescriptor = {
    configurable: true,
    enumerable: false,
    get() {
      const boundFn = originalMethod.bind(this);
      return boundFn;
    }
  };
  return adjDescriptor;
}

class Button {
  @autobind
  onClick() {
    console.log('按钮被点击', this);
  }
}

const button = new Button();
document.addEventListener('click', button.onClick);

2. 表单验证

装饰器可以很方便地实现表单验证逻辑:

function validate(min: number, max: number) {
  return function(target: any, propertyKey: string) {
    let value: number;
    
    const getter = function() {
      return value;
    };
    
    const setter = function(newVal: number) {
      if (newVal < min || newVal > max) {
        throw new Error(`值必须在 ${min}${max} 之间`);
      }
      value = newVal;
    };
    
    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter
    });
  };
}

class User {
  @validate(1, 120)
  age: number;
}

const user = new User();
user.age = 25; // 正常
user.age = 0;  // 抛出错误

装饰器的局限性

虽然装饰器很强大,但也有一些限制:

  1. 不能装饰函数声明(只能装饰类、方法、访问器、属性或参数)
  2. 装饰器不能修改类的结构(比如不能添加或删除类成员)
  3. 目前还是实验性特性,未来可能会有变化

总结

TypeScript装饰器是一个非常强大的元编程工具,它允许我们以声明式的方式为代码添加功能。通过本文的介绍,你应该已经掌握了:

  • 装饰器的基本概念和使用方法
  • 类装饰器、方法装饰器、属性装饰器的区别
  • 如何创建装饰器工厂
  • 装饰器的执行顺序
  • 装饰器在实际项目中的应用场景

装饰器在Angular、NestJS等框架中都有广泛应用,掌握好这个特性,能让你的代码更加优雅和可维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2378068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模拟jenkins+k8s自动化部署

参考 Jenkins+k8s实现自动化部署 - 掘金 手把手教你用 Jenkins + K8S 打造流水线环境 - 简书 安装插件 调整插件升级站点 (提高插件下载速度) 默认地址 https://updates.jenkins.io/update-center.json 新地址 http://mirror.xmission.com/jenkins/updates/update-center.json …

MySQL——十一、主从复制

主从复制是指将主数据库的DDL和DML操作通过二进制日志传入从库服务器中&#xff0c;然后在从库上对这些日志重新执行&#xff08;重做&#xff09;&#xff0c;从而使得从库和主库的数据保持同步。 优点&#xff1a; 主库出现问题&#xff0c;可以快速切换到从库提供服务实现读…

如何让 Google 收录 Github Pages 个人博客

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 如何确认自己的网站有没有被 google 收录 假设网址是&#xff1a;https://cyrus-studio.github.io/blog 搜索&#xff1a;site:https://cyrus-studio.github…

servlet-api

本次内容总结 1、再次学习Servlet的初始化方法 2、学习Servlet中的ServletContext和<context-param> 3、什么是业务层 4、IOC 5、过滤器 7、TransActionManager、ThreadLocal、OpenSessionInViewFilter 1、再次学习Servlet的初始化方法 1&#xff09;Servlet生命周期&…

根据输入的数据渲染柱形图

背景&#xff1a;根据不同季度的销售额&#xff0c;生成对应的柱形图&#xff0c;直观的看出差异 效果&#xff1a; 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatibl…

Java SpringBoot项目JPA查询数据demo

目录 一、前置1、IDEA创建SpringBoot项目2、基础设置、配置 二、JPA查询数据1、配置SQL server连接2、创建实体类QueryEntity.java生成Getter and Setter 3、创建Repository接口QueryRepository.java 4、创建Service服务类QueryService.java 5、创建Controller控制器类QueryCon…

vue2集成可在线编辑的思维导图(simple-mind-map)

最近要求做一个可在线编辑的思维导图&#xff0c;经过层层调研和实测&#xff0c;最简单的思维导图导图实现还得是simple-mind-map组件 simple-mind-map中文文档 当前我使用的是vue2项目&#xff0c;目前没试过是否支持vue3&#xff0c;但是看官网描述他们也给了有vue3的demo项…

如何在Windows右键新建菜单中添加自定义项,将notepad添加到新建菜单

一、简介 Windows 右键新建菜单的核心管理机制隐藏在注册表的 HKEY_CLASSES_ROOT 根键中。这里存在两种关键注册表项&#xff1a;文件扩展名项和文件类型项&#xff0c;它们共同构成了新建菜单的完整控制体系。 以常见的.txt文件为例&#xff0c;系统通过以下机制实现新建菜单…

CS016-4-unity ecs

【37】将系统转换为任务 Converting System to Job 【Unity6】使用DOTS制作RTS游戏|17小时完整版|CodeMonkey|【37】将系统转换为任务 Converting System to Job_哔哩哔哩_bilibili a. 将普通的方法&#xff0c;转化成job。第一个是写一个partial struct xxx&#xff1b;第二…

微信小程序第三方代开发模式技术调研与实践总结

🚀 微信小程序第三方代开发模式技术调研与实践总结 📖 前言 随着企业对私有化品牌运营诉求的增加,许多大型客户希望将原本由 SaaS 平台统一提供的小程序迁移至自有主体(AppID)下运行,同时又希望继续沿用 SaaS 平台的业务服务与数据托管方式。微信开放平台提供的“小程…

upload-labs通关笔记-第8关 文件上传之点绕过

目录 一、点绕过原理 二、deldot()函数 三、源码分析 四、渗透实战 1、构建脚本test8.php 2、打开靶场 3、bp开启拦截 4、点击上传 5、bp拦截 6、后缀名增加点 7、发包并获取脚本地址 8、访问脚本 本文通过《upload-labs靶场通关笔记系列》来进行upload-labs靶场的渗…

PCL PolygonMesh 与 TextureMesh 源码阅读与简单测试

Title: PCL PolygonMesh 与 TextureMesh 源码阅读与简单测试 文章目录 I . PolygonMesh1. PolygonMesh 结构体2. Vertices 结构体与点云索引3. 测试 PolygonMesh II. TextureMesh1. TextureMesh 结构体2. TexMaterial 结构体3. 纹理坐标与纹理坐标索引4. 测试 TextureMesh 以下…

量子算法:开启计算新时代的技术密码

摘要 量子算法是利用量子力学特性&#xff08;如叠加态、纠缠、干涉&#xff09;设计的计算模型&#xff0c;在特定问题上相比经典算法具有指数级加速优势。本文深入探讨了量子算法的核心原理、代表性算法及其在多个领域的应用&#xff0c;分析了量子算法面临的挑战与未来发展…

多线程代码案例-1 单例模式

单例模式 单例模式是开发中常见的设计模式。 设计模式&#xff0c;是我们在编写代码时候的一种软性的规定&#xff0c;也就是说&#xff0c;我们遵守了设计模式&#xff0c;代码的下限就有了一定的保证。设计模式有很多种&#xff0c;在不同的语言中&#xff0c;也有不同的设计…

CSS实现文本自动平衡text-wrap: balance

不再有排版孤行和寡行 我们都知道那些标题&#xff0c;最后一个单词换行并单独站在新行上&#xff0c;破坏了视觉效果&#xff0c;看起来很奇怪。当然&#xff0c;有老式的 手动换行或将内容分成不同部分。但您听说过text-wrap: balance吗&#xff1f; 通过应用text-wrap: bal…

mac M芯片运行docker-desktop异常问题

虽然mac已经迭代到m4了&#xff0c;但官方的docker-desktop运行仍然有问题&#xff0c;包括但不限于&#xff1a; 命令行docker找不到docker-desk打不开docker-desktop闪退容器起不来 尝试不同版本后&#xff0c;看到了其他可以在mac跑docker的开源方法&#xff0c;更简单、轻…

事件响应策略规范模版

事件响应策略 一、事件分级定义 根据事件对业务的影响程度和紧急程度,将事件分为 4个等级(P1-P4),明确各级事件的判定标准:、 二、响应时效承诺 响应时间(从事件确认到首次回复) P1 事件:15 分钟内响应(724 小时电话 / 工单优先接入) P2 事件:30 分钟内响应(工…

MGX:多智能体管理开发流程

MGX的多智能体团队如何通过专家混合系统采用全新方法,彻底改变开发流程,与当前的单一智能体工具截然不同。 Lovable和Cursor在自动化我们的特定开发流程方面取得了巨大飞跃,但问题是它们仅解决软件开发的单一领域。 这就是MGX(MetaGPT X)的用武之地,它是一种正在重新定…

采购流程规范化如何实现?日事清流程自动化助力需求、采购、财务高效协作

采购审批流程全靠人推进&#xff0c;内耗严重&#xff0c;效率低下&#xff1f; 花重金上了OA&#xff0c;结果功能有局限、不灵活&#xff1f; 问题出在哪里&#xff1f;是我们的要求太多、太苛刻吗&#xff1f;NO&#xff01; 流程名称&#xff1a; 采购审批管理 流程功能…

[模型部署] 3. 性能优化

&#x1f44b; 你好&#xff01;这里有实用干货与深度分享✨✨ 若有帮助&#xff0c;欢迎&#xff1a;​ &#x1f44d; 点赞 | ⭐ 收藏 | &#x1f4ac; 评论 | ➕ 关注 &#xff0c;解锁更多精彩&#xff01;​ &#x1f4c1; 收藏专栏即可第一时间获取最新推送&#x1f514;…