TypeScript装饰器:从入门到精通

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 {@logMethodadd(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 {@autobindonClick() {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.mzph.cn/web/79820.shtml

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

相关文章

【SSL证书系列】客户端如何检查中间CA签名是否由根CA签发

客户端通过以下步骤检查中间CA的签名是否由受信任的根CA签发&#xff1a; 1. 证书链的构建 服务器发送的证书链通常包含&#xff1a; • 服务器证书&#xff08;由中间CA签发&#xff09; • 中间CA证书&#xff08;由根CA签发&#xff09; • 根CA证书&#xff08;通常不发送…

【android bluetooth 协议分析 12】【A2DP详解 1】【车机侧蓝牙音乐免切源介绍】

“车机蓝牙音乐免切源” 是近年来车载系统&#xff08;IVI&#xff0c;In-Vehicle Infotainment&#xff09;中常见的一个用户体验优化功能。它主要是为了简化蓝牙音乐播放流程、减少用户操作&#xff0c;提升使用便捷性。 一、什么是“切源”&#xff1f; 在车机系统中&#…

Android usb网络共享详解

Android usb网络共享详解 文章目录 Android usb网络共享详解一、前言二、USB网络共享使用的前提1、Android设备支持adb 并且打开usb开关2、原生Settings能看到USB网络共享开关3、代码中检测USB网络共享是否支持 三、Settings 中USB网络共享代码的部分代码1、Settings\res\xml\t…

Step1

项目 SchedulerSim 已搭建完成 ✅ ⸻ ✅ 你现在拥有的&#xff1a; • &#x1f527; 两种调度器&#xff08;Round Robin SJF&#xff09; • &#x1f4e6; 模拟进程类 Process • &#x1f9f1; 清晰结构&#xff1a;OOP 风格 便于扩展 • ✍️ 主函数已演示调度器运行效…

初探 Skynet:轻量级分布式游戏服务器框架实战

在游戏服务器开发领域&#xff0c;高效、稳定且易于扩展的框架一直是开发者追求的目标。Skynet 作为一款轻量级、高性能的分布式游戏服务器框架&#xff0c;凭借其独特的设计理念和强大的功能&#xff0c;赢得了众多开发者的青睐 一.Skynet底层架构支持 1.Actor erlang 从语言…

Oracle数据库中,WITH..AS 子句用法解析

前言 在Oracle数据库中&#xff0c;WITH子句&#xff08;也成为“子查询因子化” 或“公共表表达式”&#xff0c;Common Table Expression, CTE)用于定义一个临时命名的结果集&#xff0c;这个结果集可以在后续的查询中引用。 一、基本语法 WITH sjtab AS &#xff08;SELE…

什么是卫星电话?卫星电话与普通电话有什么区别?

在信息时代&#xff0c;通信技术已渗透到人类生活的方方面面&#xff0c;但传统地面通信网络仍存在盲区&#xff0c;无论是海洋、沙漠、高山&#xff0c;还是灾害现场&#xff0c;普通手机往往因基站信号无法覆盖而失效。此时&#xff0c;卫星电话便成为连接世界的“生命线”。…

【C/C++】高阶用法_笔记

1. 模板元编程&#xff08;TMP&#xff09;与编译时计算 (1) 类型萃取与 SFINAE 类型萃取&#xff08;Type Traits&#xff09;&#xff1a;利用模板特化在编译时推断类型属性。 template<typename T> struct is_pointer { static constexpr bool value false; };templ…

鸿蒙OSUniApp 实现一个精致的日历组件#三方框架 #Uniapp

使用 UniApp 实现一个精致的日历组件 前言 最近在开发一个约会小程序时&#xff0c;需要实现一个既美观又实用的日历组件。市面上虽然有不少现成的组件库&#xff0c;但都不太符合我们的设计需求。于是&#xff0c;我决定从零开始&#xff0c;基于 UniApp 自己实现一个功能完…

PyQt5完整指南:从入门到实践

引言 PyQt5是Python编程语言的一个GUI&#xff08;图形用户界面&#xff09;工具包&#xff0c;它是Qt5应用程序框架的Python绑定。Qt是一个跨平台的C应用程序开发框架&#xff0c;被广泛用于开发GUI程序和非GUI程序。PyQt5让Python开发者能够使用Python语言享受到Qt框架的强大…

Excel的详细使用指南

### **一、Excel基础操作** #### **1. 界面与基本概念** - **工作簿&#xff08;Workbook&#xff09;**&#xff1a;一个Excel文件&#xff08;扩展名.xlsx&#xff09;。 - **工作表&#xff08;Worksheet&#xff09;**&#xff1a;工作簿中的单个表格&#xff08;默认名…

Linux grep -r 查找依赖包是否存在依赖类 Class

方法一&#xff1a;通过 Linux &#xff0c;grep -r ClassPath 命令 grep -f org.apache.kafka.connect.source.SourceRecord在 jar 包所在 lib 或者 lib/plugins 目录下执行&#xff0c;grep -r&#xff0c; flink-sql-connector-sqlserver-cdc-3.3.0.jar 中此 kafka Source…

碎片笔记|AI生成图像溯源方法源码复现经验(持续更新中……)

前言&#xff1a;本篇博客分享一些溯源方法的复现经验&#xff0c;希望能帮助到大家&#x1f389;。 目录 1. Close-set AttributionRepmixDe-FakeDNA-Net 2. Open-set AttributionPOSE 3. Single-Model AttributionOCC-CLIPLatentTracer 1. Close-set Attribution Repmix 论…

SAP Fiori Elements Object Page

🏰 SAP Fiori Elements Object Page:魔法积木城堡的建造秘密 想象一下,你曾经去过一个神奇的乐高主题公园,在那里,城堡会根据你的设计图纸自动搭建,而你只需要提供一张设计说明书,不必亲自摆放每一块积木!这就是SAP Fiori Elements Object Page的渲染魔法! 🧙‍♂…

Git 用户名与邮箱配置全解析:精准配置——基于场景的参数选择

目录 一、配置查看&#xff1a;理解多层级配置体系二、精准配置&#xff1a;基于场景的参数选择1. 仓库级配置&#xff08;推荐&#xff09;2. 用户级配置3. 系统级配置 三、历史提交信息修改1. 修改最近一次提交2. 修改多个历史提交&#xff08;危险操作&#xff09; 五、配置…

Fabric系列 - SoftHSM 软件模拟HSM

在 fabric-ca-server 上使用软件模拟的 HSM(密码卡) 功能 安装 SoftHSMv2 教程 SoftHSMv2 默认的配置文件 /etc/softhsm2.conf默认的token目录 /var/lib/softhsm/tokens/ 初始化和启动fabric-ca-server&#xff0c;需要设置一个管理员用户的名称和密码 初始化令牌 # 初始…

医学影像系统的集成与工作流优化

🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用…

转发多台px4仿真UDP数据到地面站

转发脚本的任务需求 仿真采用UDP通信方式&#xff0c;在 wsl 中仿真三台飞机&#xff0c;项目需要将一台电脑中的三台飞机的数据打包发送到另一台飞机的地面站&#xff0c;但地面站是无法直接访问另一台主机的 wsl 中的端口的&#xff0c;wsl 中的端口需要本机才能访问&#x…

FPGA图像处理(五)------ 图片水平镜像

利用bram形成双缓冲&#xff0c;如下图配置所示&#xff1a; wr_flag 表明 buffer0写 还是 buffer1写 rd_flag 表明 buffer0读 还是 buffer1读 通过写入逻辑控制(结合wr_finish) 写哪个buffer &#xff1b;写地址 进而控制ip的写使能 通过状态缓存来跳转buffer的…

微服务八股(自用)

微服务 SpringCloud 注册中心&#xff1a;Eureka 负载均衡&#xff1a;Ribbon 远程调用&#xff1a;Feign 服务熔断&#xff1a;Hystrix 网关&#xff1a;Gateway/Zuul Alibaba 配置中心&#xff1a;Nacos 负载均衡&#xff1a;Ribbon 服务调用&#xff1a;Feign 服务…