TS(五):装饰器

装饰器

    • 启用装饰器支持
    • 类装饰器
      • 定义并使用装饰器
      • 对比不使用装饰器
      • 装饰器叠加
      • 实现消息提示统一响应
      • 装饰器工厂
    • 方法装饰器
      • 登录状态验证
      • 数据请求
    • 属性装饰器
      • 大小写转换
    • 元数据
      • 安装依赖
      • 基础用法
    • 参数装饰器
      • 验证参数是否为必填项

启用装饰器支持

修改 tsconfig.json

{"experimentalDecorators": true, // 启用装饰器的实验性支持"emitDecoratorMetadata": true,  // 为源文件中的修饰声明发出设计类型元数据
}

类装饰器

定义并使用装饰器

const Decorator: ClassDecorator = (target: Function) => {console.log(target);target.prototype.sayName = () => {console.log((<any>target).firstName, (<any>target).lastName);}}@Decorator // [Function: Person] { firstName: 'Prosper', lastName: 'Lee' }
class Person {public static firstName: string = "Prosper";public static lastName: string = "Lee";
}const person: Person = new Person();
(<any>person).sayName(); // Prosper Lee

对比不使用装饰器

class Animal {public static firstName: string = "Dog";public static lastName: string = "Small";
}
Decorator(Animal); // [Function: Animal] { firstName: 'Dog', lastName: 'Small' }const animal = new Animal();
(<any>animal).sayName(); // Dog Small

装饰器叠加

const Decorator1: ClassDecorator = (target: Function) => {console.log('装饰器1', target);target.prototype.sayName = () => {console.log((<any>target).firstName, (<any>target).lastName);}}const Decorator2: ClassDecorator = (target: Function) => {console.log('装饰器2', target);target.prototype.sayHello = () => {console.log('Hello', (<any>target).firstName, (<any>target).lastName);}}@Decorator1
@Decorator2
class Person {public static firstName: string = "Prosper";public static lastName: string = "Lee";
}/*** 运行结果*      先 -> 装饰器2 [Function: Person] { firstName: 'Prosper', lastName: 'Lee' }*      后 -> 装饰器1 [Function: Person] { firstName: 'Prosper', lastName: 'Lee' }*/const person: Person = new Person();
(<any>person).sayName(); // Prosper Lee
(<any>person).sayHello(); // Hello Prosper Lee

实现消息提示统一响应

enum MessageType {log = 'log',info = 'info',warn = 'warn',error = 'error',
}interface MessageData {type: MessageType;message: string;
}const MessageDecorator: ClassDecorator = (target: Function) => {console.log(target);target.prototype.$message = (data: MessageData) => {console[data.type](data.message);}
}@MessageDecorator
class Person {public sayMessage() {(<any>this).$message({ type: MessageType.log, message: 'Log Log Log !!!' });(<any>this).$message({ type: MessageType.info, message: 'Info Info Info !!!' });(<any>this).$message({ type: MessageType.warn, message: 'Warn Warn Warn !!!' });(<any>this).$message({ type: MessageType.error, message: 'Error Error Error !!!' });}
}const person: Person = new Person();
(<any>person).sayMessage();

装饰器工厂

enum MessageType {log = 'log',info = 'info',warn = 'warn',error = 'error',
}const MessageDecorator = (type: MessageType): ClassDecorator => {return (target: Function) => {console.log(target);target.prototype.$message = (message: string) => {console[type](message);}}
}@MessageDecorator(MessageType.log)
class Person {public sayMessage() {(<any>this).$message('Log Log Log !!!');}
}const person: Person = new Person();
(<any>person).sayMessage(); // Log Log Log !!!

方法装饰器

const FuncDecorator: MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {console.log('静态成员的类的构造函数 / 实例成员的类的原型', target);console.log('成员的名称', propertyKey);console.log('成员的属性描述符', descriptor);const method = descriptor.value;// 通过装饰器修改原有方法descriptor.value = (...args: any[]) => {console.log(`修改了方法: ${propertyKey.toString()}`, args);method.apply(target, args);}
}class FuncClass {/*** @FuncDecorator* 静态成员的类的构造函数 / 实例成员的类的原型       ƒ FuncClass() { }* 成员的名称                                   funcA* 成员的属性描述符                              {writable: true, enumerable: true, configurable: true, value: ƒ}*/@FuncDecoratorpublic static funcA(a1: string, a2: number) {console.log(a1, a2);}/*** @FuncDecorator* 静态成员的类的构造函数 / 实例成员的类的原型       {funcB: ƒ, constructor: ƒ}* 成员的名称                                   funcB* 成员的属性描述符                              {writable: true, enumerable: true, configurable: true, value: ƒ}*/@FuncDecoratorpublic funcB(b1: boolean) {console.log(b1);}}/*** 结果:*      修改了方法: funcA ['Lee', 20, 1, 2, 3]*      Lee 20*/
FuncClass.funcA('Lee', 20, 1, 2, 3);/*** 结果:*      修改了方法: funcB [true, 1, 2, 3]*      true*/
const func = new FuncClass();
func.funcB(true, 1, 2, 3);

登录状态验证

在这里插入图片描述

const ValidateTokenDecorator: MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {const method = descriptor.value;descriptor.value = (...args: any[]) => {// 登录验证相关代码if (localStorage.getItem('token')) {alert('您已登录,无需重复登录,正在跳转...');} else {method.apply(target, args);}}
}class LoginController {@ValidateTokenDecoratorpublic login(username: string, password: string) {localStorage.setItem('token', `token-${username}-${password}`);alert(`登录成功!\n用户名:${username}\n密码:${password}`);}public logout() {localStorage.clear();alert('退出成功!');}
}const loginController = new LoginController();const loginBtn = document.createElement('button');
loginBtn.innerText = "登录";
loginBtn.onclick = () => loginController.login('Lee', '123456');
document.body.append(loginBtn);const logoutBtn = document.createElement('button');
logoutBtn.innerText = "退出";
logoutBtn.onclick = () => loginController.logout();
document.body.append(logoutBtn);

数据请求

在这里插入图片描述

服务端

const http = require('http');
const url = require('url');http.createServer((req, res) => {res.writeHead(200, { "Access-Control-Allow-Origin": "*" });if (req.method === 'GET') {const { query } = url.parse(req.url, true);const result = { code: 200, msg: 'success', data: query };res.end(JSON.stringify(result));} else {const result = { code: 500, msg: 'fail', data: null };res.end(JSON.stringify(result));}}).listen(8888);console.log('Server running at http://127.0.0.1:8888/');

客户端

interface RequestParams {[prop: string]: any
}interface RequestResponse {code: number;msg: string;data: any;
}enum RequestMethod {GET = "GET",POST = "POST",DELETE = "DELETE",PUT = "PUT",
}const RequestDecorator = (method: RequestMethod, url: string): MethodDecorator => {return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {const original = descriptor.value;descriptor.value = (params: RequestParams): Promise<RequestResponse | RequestParams> => {return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => {url += `?`;for (const key in params) { url += `${key}=${params[key]}&`; }const xhr: XMLHttpRequest = new XMLHttpRequest();xhr.open(method, url);xhr.send();xhr.onreadystatechange = () => {if (xhr.readyState === 4) {if (xhr.status === 200) {const result: RequestResponse = JSON.parse(xhr.response);result.code === 200 ? resolve(result) : reject(result);} else {original(params);}}}})}}
}class RequestController {@RequestDecorator(RequestMethod.GET, "http://127.0.0.1:8888/")public request_01(params: RequestParams): Promise<RequestResponse | RequestParams> { return Promise.reject(params); }@RequestDecorator(RequestMethod.POST, "http://127.0.0.1:8888/")public request_02(params: RequestParams): Promise<RequestResponse | RequestParams> { return Promise.reject(params); }@RequestDecorator(RequestMethod.POST, "http://127.0.0.1:1000/")public request_03(params: RequestParams): Promise<RequestResponse | RequestParams> { return Promise.reject(params); }}const requestController = new RequestController();const requestBtn01 = document.createElement('button');
requestBtn01.innerText = "请求 01";
requestBtn01.onclick = async () => {const res = await requestController.request_01({ username: 'Lee', password: '123456' });// {"code":200,"msg":"success","data":{"username":"Lee","password":"123456"}}console.log(res); 
};const requestBtn02 = document.createElement('button');
requestBtn02.innerText = "请求 02";
requestBtn02.onclick = async () => {const res = await requestController.request_02({ username: 'Lee', password: '123456' });// Uncaught (in promise) {code: 500, msg: 'fail', data: null}console.log(res);
};const requestBtn03 = document.createElement('button');
requestBtn03.innerText = "请求 03";
requestBtn03.onclick = async () => {const res = await requestController.request_03({ username: 'Lee', password: '123456' });// POST http://127.0.0.1:1000/?username=Lee&password=123456& net::ERR_CONNECTION_REFUSED// Uncaught (in promise) {username: 'Lee', password: '123456'}console.log(res);
};document.body.append(requestBtn01);
document.body.append(document.createElement('hr'));
document.body.append(requestBtn02);
document.body.append(document.createElement('hr'));
document.body.append(requestBtn03);

属性装饰器

大小写转换

const PropDecorator: PropertyDecorator = (target: Object, propertyKey: string | symbol) => {console.log('静态成员的类的构造函数 / 实例成员的类的原型', target);console.log('成员的名称', propertyKey);// 静态属性转大写if (typeof target === 'function') {(<any>target)[propertyKey] = (<any>target)[propertyKey].toUpperCase();} else { // 一般属性转小写let value: string;Object.defineProperty(target, propertyKey, {get: () => value.toLowerCase(),set: (v: any) => value = v,});}
}class Person {/*** @PropDecorator*      静态成员的类的构造函数 / 实例成员的类的原型          {constructor: ƒ}*      成员的名称                                      firstName*/@PropDecoratorpublic firstName: string = "Prosper";/*** @PropDecorator*      静态成员的类的构造函数 / 实例成员的类的原型          [class Person] { lastName: 'Lee' }*      成员的名称                                      lastName*/@PropDecoratorpublic static lastName: string = "Lee";}const person: Person = new Person();
console.log(`${person.firstName}${Person.lastName}!!!`); // prosperLEE!!!

元数据

安装依赖

$ npm i reflect-metadata

基础用法

import 'reflect-metadata';let person = { name: 'Lee' };// 描述name属性的基础信息
Reflect.defineMetadata('info', { key: 'string', value: 'string', desc: '这是一个名字字段!' }, person, 'name');// 打印name字段的基础信息
const info = Reflect.getMetadata('info', person, 'name');
console.log(info); // { key: 'string', value: 'string', desc: '这是一个名字字段!' }

参数装饰器

验证参数是否为必填项

import 'reflect-metadata';interface ErrorParam {parameterIndex: number;message: string;
}enum Sex {Empty = '',Sir = '先生',Madam = '女士',
}/*** 传参验证方法装饰器* @param target 静态成员的类的构造函数 / 实例成员的类的原型* @param propertyKey 成员的名称* @param descriptor 成员的属性描述符*/
const ValidateDecorator: MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {const original = descriptor.value;descriptor.value = (...args: any) => {const rules: ErrorParam[] = Reflect.getMetadata('rules', target, propertyKey) || [];rules.forEach((rule: ErrorParam) => {if (args[rule.parameterIndex] === undefined) {throw new Error(rule.message);}})original.apply(target, args);}
}/*** 参数装饰器工厂* @param field 字段名* @returns 参数装饰器*/
const RequiredDecorator = (field: string): ParameterDecorator => {return (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => {if (propertyKey) {let rules: ErrorParam[] = [{ parameterIndex, message: `缺少参数: '${field}'` },...(Reflect.getMetadata('rules', target, propertyKey) || []),];Reflect.defineMetadata('rules', rules, target, propertyKey);}}
}class Person {@ValidateDecoratorpublic message(@RequiredDecorator('敬语')honorific: string,@RequiredDecorator('姓名')name: string,sex: Sex) {console.log(`${honorific} ${name} ${sex ? sex : Sex.Empty}!!!`);}}const person = new Person();person.message();                          // Error: 缺少参数: '敬语'
person.message('尊敬的');                   // Error: 缺少参数: '姓名'
person.message('尊敬的', 'Lee');            // 尊敬的 Lee !!!
person.message('尊敬的', 'Lee', Sex.Sir);   // 尊敬的 Lee 先生!!!

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

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

相关文章

和鲸 ModelWhale 与华为 OceanStor 2910 计算型存储完成兼容性测试

数智化时代&#xff0c;数据总量的爆炸性增长伴随着人工智能、云计算等技术的发展&#xff0c;加速催化了公众对于数据存储与应用的多元化需求。同时&#xff0c;数据也是重要的基础资源和战略资源&#xff0c;需要严格保障其安全性、完整性。搭建国产数据基础设施底座&#xf…

信息系统项目管理师第四版学习笔记——高级项目管理

项目集管理 项目集管理角色和职责 在项目集管理中涉及的相关角色主要包括&#xff1a;项目集发起人、项目集指导委员会、项目集经理、其他影响项目集的干系人。 项目集发起人和收益人是负责承诺将组织的资源应用于项目集&#xff0c;并致力于使项目集取得成功的人。 项目集…

实验2.1.2 交换机的常用配置

项目2 交换技术的位置 活动2 交换机的常用配置 一、具体要求&#xff1a; &#xff08;1&#xff09;添加1台计算机&#xff0c;将标签名更改为PC1。 &#xff08;2&#xff09;添加1台S3700-26C-HI交换机&#xff0c;标签名为SWA&#xff0c;将交换机的名称设置为SWA。 &am…

华为云云耀云服务器L实例评测 | 实例评测使用之硬件参数评测:华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu

华为云云耀云服务器L实例评测 &#xff5c; 实例评测使用之硬件参数评测&#xff1a;华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器…

关键词搜索快手商品列表数据,快手商品列表数据接口,快手API接口

在网页抓取方面&#xff0c;可以使用 Python、Java 等编程语言编写程序&#xff0c;通过模拟 HTTP 请求&#xff0c;获取快手网站上的商品页面。在数据提取方面&#xff0c;可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是&#xff0c;快手网站…

Android Studio: unrecognized Attribute name MODULE

错误完整代码&#xff1a; &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd; (1.8.0_291) &#xfffd;г&#xfffd;&#xfffd;&#xfffd;&#xfffd;쳣&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xff…

17个开源的Go语言博客和CMS解决方案

Go语言&#xff0c;也称为Golang&#xff0c;是一种为构建高效、可靠和可扩展软件而设计的开源编程语言。它于2007年在Google开发&#xff0c;现在广泛用于开发Web应用程序、网络工具和系统软件。 为什么使用基于Go的CMS解决方案&#xff1f; 这些优势使Go成为开发可扩展、高…

ansible的介绍安装与模块

目录 一、ansible简介 二、ansible特点 三、Ansible核心组件与工作原理 1、核心组件 2、工作原理 四、ansible的安装 五、ansible 命令行模块 1&#xff0e;command 模块 2&#xff0e;shell 模块 3&#xff0e;cron 模块 4&#xff0e;user 模块 5&#xff0e;group 模…

如何在Synology群晖DSM中为不同用户设置权限

在使用Synology 群晖NAS时往往需要为不同的用户添加各自的账户权限&#xff0c;我们希望他们可以自由使用自己的主文件夹&#xff0c;但不要互相看到别人的主文件夹&#xff0c;更不要互相浏览别人主文件夹下的内容&#xff0c;应该怎么设置呢&#xff1f;DSM系统中有完善的文件…

阿里云10M公网收费价格表(一年和1个月报价)

阿里云服务器10M带宽收费价格表&#xff0c;阿里云服务器上海地域10M带宽一年优惠价格5355元&#xff0c;10M带宽一个月525元&#xff0c;地域不同带宽价格不同&#xff0c;阿里云服务器网以华东1&#xff08;上海&#xff09;地域为例&#xff0c;5M及5M以下带宽按照23元一个月…

UI设计师岗位的基本职责八篇

UI设计师岗位的基本职责1 职责&#xff1a; 1. 负责公司互联网产品app、web、h5等的用户界面设计工作; 2. 负责运营活动相关的平面及视频设计支持; 3. 负责完成产品相关的界面、图标、动画等的图形界面设计&#xff0c;并参与制定、编写产品视觉设计规范文档; 4. 整理和分…

多服务器云探针源码(服务器云监控)/多服务器多节点_云监控程序python源码

源码简介&#xff1a; 多服务器云探针源码(服务器云监控),支持python多服务器多节点&#xff0c;云监控程序源码。它是一款很实用的云探针和服务器云监控程序源码。使用它可以帮助管理员能够快速监控和管理各种服务器和节点&#xff0c;实用性强。 源码链接&#xff1a; 网盘…

XXE漏洞复现实操

文章目录 一、漏洞原理二、验证payload三、没有回显时的验证四、漏洞特征五、读取文件六、Base64加密读取七、端口检测八、使用php检测端口九、dtd外部实体读取文件十、Xxe漏洞防御 一、漏洞原理 (1)XXE漏洞全称XML External Entity Injection&#xff0c;即xmI外部实体注入漏…

CTF/AWD竞赛标准参考书+实战指南:《AWD特训营》

文章目录 前言内容简介读者对象目录介绍 前言 随着网络安全问题日益凸显&#xff0c;国家对网络安全人才的需求持续增长&#xff0c;其中&#xff0c;网络安全竞赛在国家以及企业的人才培养和选拔中扮演着至关重要的角色。 在数字化时代&#xff0c;企业为了应对日益增长的攻…

【智能家居项目】裸机版本——网卡设备接入输入子系统 | 业务子系统 | 整体效果展示

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《智能家居项目》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f95e;网卡设备接入输入子系统&#x1f354;测试 &#x1f95e;业务子系统&#…

【业务功能篇 131】23种设计模式介绍

第一章 设计模式概述 1.1 代码质量好坏如何评价? 要想学习设计模式呢 我们就必须搞清楚设计模式到底在我们的编程过程中起到了怎样的作用,在编程世界中它处在一个什么样的位置,它到底是一种抽象的设计思想,还是一套具体的落地方案. 在学习设计模式之前呢 我们需要了解一下 代…

CRM系统:快速实现外勤出差人员远程访问企业提升工作效率!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《速学数据结构》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 快速实现外勤出差人员远程访问企业CRM系统前言1. 无需公网IP&#xff0c;高效低成本实现CRM系统远程访问1.1 下…

Docker 的数据管理和Dockerfile镜像的创建

目录 Docker 的数据管理 管理 Docker 容器中数据的方式 端口映射 容器互联&#xff08;使用centos镜像&#xff09; Docker 镜像的创建 Dockerfile 操作常用的指令 编写 Dockerfile 时格式 Dockerfile 案例 Docker 的数据管理 管理 Docker 容器中数据的方式 管理 Doc…

C# AnimeGAN 漫画风格迁移 动漫风格迁移 图像卡通化 图像动漫化

效果 项目 模型 animeganv3_H40_model.onnx animeganv3_H50_model.onnx animeganv3_H64_model.onnx AnimeGANv3_JP_face_v1.0.onnx AnimeGANv3_PortraitSketch_25.onnx Hayao-60.onnx Hayao_64.onnx Paprika_54.onnx Shinkai_53.onnx 下载 可执行文件exe下载 源码下载

JAVA IO 流分类整理

一、JAVA IO 流分为三种&#xff1a; 1、按照流向&#xff1a;输入流和输出流 2、按照操作单元&#xff1a;字节流和字符流 3、按照流的角色&#xff1a;节点流和处理流 二、JAVA IO 流的40多个类都派生自4个抽象类 1、字节输入流&#xff08;InputStream&#xff09; 、 2、字…