【TS学习】(24)什么是装饰器

在 TypeScript 中,装饰器(Decorators) 是一种特殊的声明,用于为类、类成员(属性、方法、访问器)、方法参数或整个类添加元数据或修改其行为。装饰器是 JavaScript 和 TypeScript 的实验性特性,广泛应用于框架开发(如 Angular)和元编程场景。


1. 启用装饰器

在 TypeScript 中,默认情况下装饰器是禁用的。要启用装饰器支持,需要在 tsconfig.json 文件中设置以下选项:

{"compilerOptions": {"experimentalDecorators": true}
}

2. 装饰器的基本概念

(1) 定义
  • 装饰器是一个函数,它接收一个目标对象作为参数,并可以对其进行修改或扩展。
  • 装饰器通过 @ 符号应用到目标上。
(2) 语法
function Decorator(target: any): void {// 修改或扩展 target 的行为
}@Decorator
class MyClass {}

3. 类装饰器

(1) 定义
  • 类装饰器应用于类构造函数本身。
  • 它可以用来修改类的行为或添加元数据。
(2) 示例
function LogClass(constructor: Function) {console.log(`Class ${constructor.name} has been defined.`);
}@LogClass
class User {name: string;constructor(name: string) {this.name = name;}
}const user = new User("Alice"); // 输出 "Class User has been defined."

在这里:

  • LogClass 是一个类装饰器,用于记录类的定义。

4. 方法装饰器

(1) 定义
  • 方法装饰器应用于类的方法。
  • 它可以用来修改方法的行为或添加元数据。
(2) 示例
function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Calling method '${propertyKey}' with arguments: ${args}`);return originalMethod.apply(this, args);};
}class Calculator {@LogMethodadd(a: number, b: number): number {return a + b;}
}const calculator = new Calculator();
console.log(calculator.add(2, 3));
// 输出:
// Calling method 'add' with arguments: 2,3
// 5

在这里:

  • LogMethod 是一个方法装饰器,用于记录方法调用及其参数。

5. 属性装饰器

(1) 定义
  • 属性装饰器应用于类的属性。
  • 它可以用来添加元数据或修改属性的行为。
(2) 示例
function LogProperty(target: any, propertyKey: string) {let value: any;const getter = function () {console.log(`Getting value of '${propertyKey}'`);return value;};const setter = function (newValue: any) {console.log(`Setting value of '${propertyKey}' to ${newValue}`);value = newValue;};Object.defineProperty(target, propertyKey, {get: getter,set: setter,enumerable: true,configurable: true,});
}class User {@LogPropertyname: string;constructor(name: string) {this.name = name;}
}const user = new User("Alice");
console.log(user.name); // 输出 "Getting value of 'name'" 和 "Alice"
user.name = "Bob";      // 输出 "Setting value of 'name' to Bob"

在这里:

  • LogProperty 是一个属性装饰器,用于记录属性的访问和修改。

6. 参数装饰器

(1) 定义
  • 参数装饰器应用于方法的参数。
  • 它可以用来添加元数据或记录参数信息。
(2) 示例
function LogParameter(target: any, propertyKey: string | symbol, parameterIndex: number) {console.log(`Parameter at index ${parameterIndex} in method '${String(propertyKey)}' is decorated.`);
}class Calculator {add(@LogParameter a: number, @LogParameter b: number): number {return a + b;}
}const calculator = new Calculator();
calculator.add(2, 3);
// 输出:
// Parameter at index 0 in method 'add' is decorated.
// Parameter at index 1 in method 'add' is decorated.

在这里:

  • LogParameter 是一个参数装饰器,用于记录方法参数的索引和名称。

7. 访问器装饰器

(1) 定义
  • 访问器装饰器应用于类的存取器(getter 和 setter)。
  • 它可以用来修改存取器的行为或添加元数据。
(2) 示例
function LogAccessor(target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalGetter = descriptor.get;const originalSetter = descriptor.set;descriptor.get = function () {console.log(`Getting value of '${propertyKey}'`);return originalGetter?.apply(this);};descriptor.set = function (value: any) {console.log(`Setting value of '${propertyKey}' to ${value}`);originalSetter?.apply(this, [value]);};
}class User {private _name: string;constructor(name: string) {this._name = name;}@LogAccessorget name(): string {return this._name;}set name(value: string) {this._name = value;}
}const user = new User("Alice");
console.log(user.name); // 输出 "Getting value of 'name'" 和 "Alice"
user.name = "Bob";      // 输出 "Setting value of 'name' to Bob"

在这里:

  • LogAccessor 是一个访问器装饰器,用于记录存取器的访问和修改。

8. 装饰器工厂

装饰器工厂是一个返回装饰器函数的函数,允许传递参数以动态配置装饰器。

示例
function Log(message: string) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`${message}: Calling method '${propertyKey}' with arguments: ${args}`);return originalMethod.apply(this, args);};};
}class Calculator {@Log("Debug Info")add(a: number, b: number): number {return a + b;}
}const calculator = new Calculator();
calculator.add(2, 3);
// 输出:
// Debug Info: Calling method 'add' with arguments: 2,3

在这里:

  • Log 是一个装饰器工厂,允许传递自定义消息。

9. 实际应用场景

(1) 日志记录
  • 使用装饰器记录方法调用、参数和返回值。
(2) 权限控制
  • 使用装饰器检查用户权限,限制对某些方法的访问。
示例
function RequireRole(role: string) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {if (role === "admin") {return originalMethod.apply(this, args);} else {throw new Error("Permission denied");}};};
}class AdminPanel {@RequireRole("admin")deleteUser(userId: number): void {console.log(`Deleting user with ID ${userId}`);}
}const panel = new AdminPanel();
panel.deleteUser(123); // 如果 role 不是 "admin",会抛出错误

10. 总结

特性描述
类装饰器应用于类构造函数,用于修改类的行为或添加元数据。
方法装饰器应用于类的方法,用于修改方法的行为或添加元数据。
属性装饰器应用于类的属性,用于添加元数据或修改属性的行为。
参数装饰器应用于方法的参数,用于记录参数信息或添加元数据。
访问器装饰器应用于存取器,用于修改存取器的行为或添加元数据。
装饰器工厂返回装饰器函数的函数,允许动态配置装饰器。

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

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

相关文章

datagrip如何连接数据库

datagrip连接数据库的步骤 2025版本 想要链接数据库是需要一个jar包的,所以将上面进行删除之后,需要下载一个jar包 那么这个时候需要链接上传一个mysql链接的jar包 选择核心驱动类 上述操作完成之后,然后点击apply再点击ok即可 如下图说明my…

菊风RTC 2.0 开发者文档正式发布,解锁音视频新体验!

重磅发布! 开发者们,菊风实时音视频2.0文档已正式发布上线,为您提供更清晰、更高效的开发支持!让菊风实时音视频2.0为您的音视频应用加速~ 菊风实时音视频2.0聚焦性能升级、体验升级、录制服务升级,助力视频通话、语…

轻量级碎片化笔记memos本地NAS部署与跨平台跨网络同步笔记实战

文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 推荐 ​ 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站 前言…

【Vue #2】脚手架 指令

一、脚手架 脚手架:一个保证各项工作顺利开展的平台,方便我们 拿来就用,零配置 1. Vue 代码开发方式 相比直接 script 引入 vue 源码,有没有更好的方式编写vue代码呢? ① 传统开发模式: 基于html文件开发Vue&…

ArkTS语言入门之接口、泛型、空安全、特殊运算符等

前言 臭宝们,今天我们来学习ArkTS中最后的一些内容。 实现接口 包含implements子句的类必须实现列出的接口中定义的所有方法,但使用默认实现定义的方法除外。 interface DateInterface {now(): string; } class MyDate implements DateInterface {no…

Maven超级详细安装部署

1.到底什么是Maven?搞清楚这个 Maven 是一个项目管理工具,主要用于 Java 项目的构建、依赖管理和文档生成。 它基于项目对象模型(POM),通过 pom.xml 文件定义项目的配置。 (简单说破:就是工程…

高并发内存池(三):PageCache(页缓存)的实现

前言: 在前两期内容中,我们深入探讨了内存管理机制中在 ThreadCache 和 CentralCache两个层级进行内存申请的具体实现。这两层缓存作为高效的内存分配策略,能够快速响应线程的内存需求,减少锁竞争,提升程序性能。 本期…

机器学习 | 强化学习方法分类汇总 | 概念向

文章目录 📚Model-Free RL vs Model-Based RL🐇核心定义🐇核心区别📚Policy-Based RL vs Value-Based RL🐇核心定义🐇 核心区别📚Monte-Carlo update vs Temporal-Difference update🐇核心定义🐇核心区别📚On-Policy vs Off-Policy🐇核心定义🐇核心区别…

GSO-YOLO:基于全局稳定性优化的建筑工地目标检测算法解析

论文地址:https://arxiv.org/pdf/2407.00906 1. 论文概述 《GSO-YOLO: Global Stability Optimization YOLO for Construction Site Detection》提出了一种针对建筑工地复杂场景优化的目标检测模型。通过融合全局优化模块(GOM)​、稳定捕捉模块(SCM)​和创新的AIoU损失函…

Java学习手册:JVM、JRE和JDK的关系

在Java生态系统中,JVM(Java虚拟机)、JRE(Java运行时环境)和JDK(Java开发工具包)是三个核心概念。它们共同构成了Java语言运行和开发的基础。理解它们之间的关系对于Java开发者来说至关重要。本文…

lanqiaoOJ 2489 进制

//x的初始值一定要设置为0,否则测试的答案是对的,但是通不过去 #include<bits/stdc.h> using namespace std; const int N50; int a[N]; using lllong long; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); string s"2021ABCD"; for(int i…

Python基础知识点(类和对象)

""" 编程思维---解决问题的方式方法 面向过程---C语言 面向对象---C java python python中封装类的语法 class 类名&#xff08;父类&#xff09; 类体 注意&#xff1a; 1.类名--约定 大驼峰法 首字母要大写 2.父类如果有的话就写&#xff0c;没有的话…

记录一下学习docker的命令(不断补充中)

#2025-04-10,22:12############### 在wsl2中安装了ubuntu24.04.1后有部署了docker&#xff0c; 如果没有启动docker可以通过下列命令启动docker&#xff1a; sudo systemctl start docker 执行下列命令可以看到docker状态&#xff0c;并不占用控制台的命令&#xff1a; su…

【01BFS】# P4667 [BalticOI 2011] Switch the Lamp On 电路维修 (Day1)|普及+

本文涉及知识点 CBFS算法 题目描述 Casper is designing an electronic circuit on a N M N \times M NM rectangular grid plate. There are N M N \times M NM square tiles that are aligned to the grid on the plate. Two (out of four) opposite corners of each …

参考平面跨分割情况下的信号回流

前言&#xff1a;弄清楚信号的回流路径&#xff0c;是学习EMC和高速的第一步&#xff01; 如果我们不管信号的回流路径&#xff0c;会造成什么后果&#xff1f;1、信号完整性问题&#xff0c;信号的回流路径不连续会导致信号反射、衰减和失真。2、信号衰减和噪声干扰&#xff…

almalinux 8 9 升级到指定版本

almalinux 8 update 指定版本 almalinux历史版 所有版本almalinux最新版 所有版本vault历史版 almalinux最新版 (https://repo.almalinux.org )地址后面增加不同名称 echo "delete repos" rm -rf /etc/yum.repos.d/*echo "new almalinux repo" cat <&…

阿里云CDN应对DDoS攻击策略

阿里云CDN遭遇DDoS攻击时&#xff0c;可通过以下综合措施进行应对&#xff0c;保障服务的稳定性和可用性&#xff1a; 1. 启用阿里云DDoS防护服务 阿里云提供专业的DDoS防护服务&#xff0c;通过流量清洗中心过滤恶意流量&#xff0c;确保合法请求正常传输。该服务支持按需选…

CentOS Stream release 9安装 MySQL(一)

在 CentOS Stream 上安装 MySQL 的方法与传统的 CentOS 类似&#xff0c;但由于 CentOS Stream 的软件包更新策略不同&#xff0c;可能会遇到一些依赖问题。以下是详细安装步骤&#xff1a; 1. 添加 MySQL 官方 Yum 仓库 sudo rpm -Uvh https://dev.mysql.com/get/mysql80-co…

数据结构 | 证明链表环结构是否存在

❤个人主页&#xff1a; 链表环结构 0.前言1.环形链表&#xff08;基础&#xff09;2.环形链表Ⅱ&#xff08;中等&#xff09;3.证明相遇条件及结论3.1 问题1特殊情况证明3.2 问题1普适性证明 0.前言 在这篇博客中&#xff0c;我们将深入探讨链表环结构的检测方法&#xff1a;…

数字世界的免疫系统:恶意流量检测如何守护网络安全

在2023年全球网络安全威胁报告中,某跨国电商平台每秒拦截的恶意请求峰值达到217万次,这个数字背后是无数黑客精心设计的自动化攻击脚本。恶意流量如同数字世界的埃博拉病毒,正在以指数级速度进化,传统安全防线频频失守。这场没有硝烟的战争中,恶意流量检测技术已成为守护网…