TS学习笔记十:装饰器及三斜线指令

  本节介绍TS中的装饰器和三斜线指令, 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。
  三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。

  1. 讲解视频

    20240116-205052装饰器


    TS学习笔记二十:三斜线指令

    104)(image-https://video-community.csdnimg.cn/vod-84deb4/901d2766b4d471eebfab5017e1e90102/snapshots/e0f8d1fe08404a27bbb052c04619311a-00005.jpg?auth_key=4859053547-0-0-7b5ee6117f96be71df4a2617251f66a1)(title-TS学习笔记二十:三斜线指令)]

  2. B站视频

    TS学习笔记十九:Mixins组件复用

    o(video-qGsTIynP-1706149194130)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=793984818)(image-https://img-blog.csdnimg.cn/img_convert/ced6f103f671e196372c6d5541657093.jpeg)(title-TS学习笔记十九:Mixins组件复用)]

    TS学习笔记十八:装饰器

    )]

  3. 西瓜视频
    https://www.ixigua.com/7324864397644562998
    在这里插入图片描述

一、装饰器

  装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。在ts中目前是实验性的特性,要启用需要在命令行或tsconfig.json里启用experimentalDecorators编译器选项,具体启用方式如下:
命令行:

tsc --target ES5 --experimentalDecorators

tsconfig.json:

{"compilerOptions": {"target": "ES5","experimentalDecorators": true}
}

  装饰器是一个特殊的类型声明,能够被附加到类声明、方法、访问符、属性、参数等上,使用@expr的形式进行附加,expr求值后必须为一个函数,会在运行时被调用,被装饰的声明信息作为参数传入,如下:

function sealed(target){
}

  定义后可以@sealed(‘’)的方式进行使用。
1. 装饰器工厂
  要定制一个装饰器并应用到一个声明上,需要写一个装饰器工厂,装饰器工厂是一个简单的函数,并返回一个表达式,此表达式在运行的时候调用。

function color(value: string) { // 这是一个装饰器工厂return function (target) { //  这是装饰器// do something with "target" and "value"...}
}

2.装饰器组合
  多个装饰器可以同时应用到一个声明上:

@a @b x
@a
@b
x

  可以在同一行,也可以在不同行,多个声明时求值方式与符合函数类型,即a(b(x)),具体如下:

  1. 由上至下依次对装饰器表达式求值
  2. 求值的结果会被当做函数,由下至上依次调用。
function f() {console.log("f(): evaluated");return function (target, propertyKey: string, descriptor: PropertyDescriptor) {console.log("f(): called");}
}function g() {console.log("g(): evaluated");return function (target, propertyKey: string, descriptor: PropertyDescriptor) {console.log("g(): called");}
}class C {@f()@g()method() {}
}

  调用结果如下:

f(): evaluated
g(): evaluated
g(): called
f(): called

3. 装饰器求值
  类中不同声明上的装饰器的应用顺序如下:

  1. 参数装饰器,其次是方法,访问符,或属性装饰器应用到每个实例成员。
  2. 参数装饰器,其次是方法,访问符,或属性装饰器应用到每个静态成员。
  3. 参数装饰器应用到构造函数。
  4. 类装饰器应用到类。

4.类装饰器
  类装饰器在类声明之前被调用,应用于构造函数,可以用来监视,修改或替换类的具体定义,不能再声明文件.d.ts及外部上下文中使用。类装饰器的表达式会被当做函数调用,调用时类的构造函数当做其参数。如果类装饰器返回一个值,会使用提供的构造函数来替换类的声明。如果返回的是一个新的构造函数,需要手动处理原型链的内容,ts不会自动处理。

@sealed
class Greeter {greeting: string;constructor(message: string) {this.greeting = message;}greet() {return "Hello, " + this.greeting;}
}
function sealed(constructor: Function) {Object.seal(constructor);Object.seal(constructor.prototype);
}

  上述示例当@sealed装饰器被执行时,会封闭此类的构造函数和原型,封闭后将不可扩展。

5.方法装饰器
  方法装饰器在声明一个方法之前,会被应用到方法的属性描述符上,可用来监视,修改或替换方法的定义,不能用在声明文件.d.ts、重载或者任何外部上下文中。方法装饰器的表达式会被当做函数调用,调用时传入以下三个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。
      如果代码的目标版本小于es5,则成员的描述符为undefined。如果方法返回一个值,会被当做方法的属性描述符。如果目标版本小于es5,返回值会被忽略。
class Greeter {greeting: string;constructor(message: string) {this.greeting = message;}@enumerable(false)greet() {return "Hello, " + this.greeting;}
}
function enumerable(value: boolean) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {descriptor.enumerable = value;};
}

  上述示例中当@enumerable(false)被调用时,会修改属性描述符的enumerable 。

6.访问器装饰器
  访问器装饰器声明在一个访问器声明之前,应用于访问器的属性描述符,可用来监视,修改和替换一个访问器的定义,不能在声明文件.d.ts或任何外部上下中。
  ts不允许同时装饰一个成员的get和set访问器,一个成员的所有装饰必须引用在文档顺序的第一个访问器上,因为装饰器应用于一个属性描述符时,已经联合了get和set访问器,不用分开声明。
  访问器装饰器表达式会在运行时当做函数被调用,调用时传入一下三个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。
      代码输出目标小于es5,时成员属性描述符参数是undefined。如果访问器返回一个值,会被当做方法的属性描述符。如果代码目标小于es5时,返回值会被忽略。
class Point {private _x: number;private _y: number;constructor(x: number, y: number) {this._x = x;this._y = y;}@configurable(false)get x() { return this._x; }@configurable(false)get y() { return this._y; }
}
function configurable(value: boolean) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {descriptor.configurable = value;};
}

7.属性装饰器
  属性装饰器声明在一个属性之前,不能在声明文件.d.ts及任何外部上下文中。属性装饰器表达式会在运行时当做函数被调用,调用时传入2个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。

  属性描述符不会做为参数传入属性装饰器,如果属性装饰器返回一个值,会被当做方法的属性描述符,如果目标小于es5返回值会被忽略。如果装饰器返回一个值,会被当做方法的属性描述符。

class Greeter {@format("Hello, %s")greeting: string;constructor(message: string) {this.greeting = message;}greet() {let formatString = getFormat(this, "greeting");return formatString.replace("%s", this.greeting);}
}
import "reflect-metadata";
const formatMetadataKey = Symbol("format");
function format(formatString: string) {return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}

  上述示例中当@format(“Hello, %s”)被调用时,会添加一条这个属性的元数据,通过reflect-metadata库里的Reflect.metadata函数,当getFormat被调用时,会读取格式的元数据。

8.参数装饰器
  参数装饰器声明在一个参数之前,应用于类型构造函数或方法声明,不能用在声明文件.d.ts、重载或其它外部上下文里,参数装饰器表达式会被当做函数被调用,调用时传入3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 参数在函数参数列表中的索引。

  参数装饰器只能用来监听一个方法的参数是否被传入,参数装饰器的返回值会被忽略。

class Greeter {greeting: string;constructor(message: string) {this.greeting = message;}@validategreet(@required name: string) {return "Hello " + name + ", " + this.greeting;}
}
import "reflect-metadata";const requiredMetadataKey = Symbol("required");function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];existingRequiredParameters.push(parameterIndex);Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {let method = descriptor.value;descriptor.value = function () {let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);if (requiredParameters) {for (let parameterIndex of requiredParameters) {if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {throw new Error("Missing required argument.");}}}return method.apply(this, arguments);}
}

  上述示例中使用@required添加了元数据实体把参数标记为必须得,@validate装饰器包裹函数,在调用原先的函数前验证函数参数。
9.元数据
  reflect-metadata是处理元数据的库,不是es的标准库,需要额外引入,安装指令:npm i reflect-metadata --save。ts支持为带有装饰器的声明生成元数据,需要在命令行或jsconfig.json中开启emitDecoratorMetadata编译选项。
命令行:

tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata

jsconfig.json:

{"compilerOptions": {"target": "ES5","experimentalDecorators": true,"emitDecoratorMetadata": true}
}

  启用后,安装了reflect-metadata并引入的情况下,类型信息可以在运行时调用:

import "reflect-metadata";class Point {x: number;y: number;
}class Line {private _p0: Point;private _p1: Point;@validateset p0(value: Point) { this._p0 = value; }get p0() { return this._p0; }@validateset p1(value: Point) { this._p1 = value; }get p1() { return this._p1; }
}function validate<T>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {let set = descriptor.set;descriptor.set = function (value: T) {let type = Reflect.getMetadata("design:type", target, propertyKey);if (!(value instanceof type)) {throw new TypeError("Invalid type.");}}
}

  ts编译器可通过@Reflect.metadata装饰器注入设计阶段的类型信息:

class Line {private _p0: Point;private _p1: Point;@validate@Reflect.metadata("design:type", Point)set p0(value: Point) { this._p0 = value; }get p0() { return this._p0; }@validate@Reflect.metadata("design:type", Point)set p1(value: Point) { this._p1 = value; }get p1() { return this._p1; }
}

二、Mixins

  mixin是一种创建可重用组件创建类的方式:

// Disposable Mixin
class Disposable {isDisposed: boolean;dispose() {this.isDisposed = true;}}// Activatable Mixin
class Activatable {isActive: boolean;activate() {this.isActive = true;}deactivate() {this.isActive = false;}
}class SmartObject implements Disposable, Activatable {constructor() {setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);}interact() {this.activate();}// DisposableisDisposed: boolean = false;dispose: () => void;// ActivatableisActive: boolean = false;activate: () => void;deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable]);let smartObj = new SmartObject();
setTimeout(() => smartObj.interact(), 1000);function applyMixins(derivedCtor: any, baseCtors: any[]) {baseCtors.forEach(baseCtor => {Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {derivedCtor.prototype[name] = baseCtor.prototype[name];});});
}

  上述示例中定义了两个类,作为mixins,每个类都有自己的行为和功能:

// Disposable Mixin
class Disposable {isDisposed: boolean;dispose() {this.isDisposed = true;}}
// Activatable Mixin
class Activatable {isActive: boolean;activate() {this.isActive = true;}deactivate() {this.isActive = false;}
}

  创建一个新的类,让其具有所有属性:

class SmartObject implements Disposable, Activatable {
// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;
}

  示例中使用implements,把类当做接口使用,仅使用类的类型不继承具体的声明,为mixin创建出占位属性,在通过mixins混入定义的类,完成实现部分,这样就不用实现可以直接使用:

applyMixins(SmartObject, [Disposable, Activatable]);

  applyMixins会遍历mixins上的所有属性,并复制到目标上去,把之前的占位符属性替换成真正的实现代码:

function applyMixins(derivedCtor: any, baseCtors: any[]) {baseCtors.forEach(baseCtor => {Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {derivedCtor.prototype[name] = baseCtor.prototype[name];})});
}

三、三斜线指令

  三斜线指令包含单个XML标签的单个注释,会做为编译器指令使用,三斜线指令只能放在包含它的文件的顶端,一个三斜线指令的前面只能出现单行或多行注释,如果出现在一个语句或声明之后,会被当做普通的单行注释,并不具有特殊含义。
  /// 用于声明文件间的依赖,用于告诉编译器在编译过程中要引入的额外的文件。
  使用–out或–outFile时,可以作为调整输出内容属性的一种方法。

  1. 预处理输入文件
      编译器会对输入文件进行预处理,预处理时解析所有的三斜线引用指令,此过程中额外的文件会加到编译过程中。
    引用不存在的文件会报错,一个文件用三斜线指令引用自己也会报错。
  2. 使用 --noResolve
      指定了–noResolve编译选项,三斜线引用将被忽略,不会增加新文件也不会改变改定文件的顺序。
    /// :
      此指令把一个文件标记成默认库,告诉编译器在编译过程中不要包含这个默认库,和命令行上使用–noLib相似,当传递了–skipDefaultLibCheck时,编译器只会忽略检查带有/// 的文件。

/// :
  默认情况下生成的amd模块是匿名的,amd-module指令允许给编译器传入一个可选的模块名。
amdModule.ts:

///<amd-module name='NamedModule'/>
export class C {
}

编译后:

define("NamedModule", ["require", "exports"], function (require, exports) {var C = (function () {function C() {}return C;})();exports.C = C;
});

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

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

相关文章

基于一款热门大屏可视化设计器使用教程

乐吾乐大屏可视化设计器是一个用于创建和定制大屏幕数据可视化展示的工具&#xff0c;支持零代码实现物联网、工业智能制造等领域的可视化大屏、触摸屏端UI以及工控可视化的解决方案。同时也是一个Web组态工具&#xff0c;支持2D、3D等多种形式&#xff0c;用于构建具有实时数据…

华硕ASUS K43SD笔记本安装win7X64(ventoy为入口以支撑一盘多系统);友善之臂mini2440开发板学习

记录 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 1. MBR样式常规安装win7X64Sp1 (华硕 K43SD 安装 win7X64 ) 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 (常规安装) 设置: 禁用UEFI 启用AHCI ventoy制作MBR(非UEFI)方式的启动U盘 U盘中放cn_windows_7_ultimate_wit…

TCP 三次握手以及滑动窗口

TCP 三次握手 简介&#xff1a; TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的 “ 连接” &#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以…

【机器学习300问】19、深度学习和机器学习什么关系?

之前的文章都聚焦在传统的机器学习上&#xff0c;作为入门&#xff0c;学了许多机器学习的基础。往后的文章我会穿插着机器学习和深度学习的内容进行&#xff0c;所有有必要在这里先说下两者的关系。 一、从范围上讲 深度学习和机器学习都是人工智能的一个子领域&#xff0c;它…

微信会议活动微展示在线活动报名源码系统 带完整的搭建教程

随着微信的普及&#xff0c;微信会议活动已成为企业、团体和个人进行信息交流、业务推广和品牌宣传的重要平台。然而&#xff0c;如何高效地管理、展示和报名参加这些会议活动&#xff0c;一直是许多组织者面临的难题。下面&#xff0c;小编给大家分享一款微信会议活动微展示在…

江科大STM32 中

目录 6、TIM&#xff08;Timer&#xff09;定时器基本定时器通用定时器高级定时器示例程序&#xff08;定时器定时中断&定时器外部时钟&#xff09;TIM输出比较示例程序&#xff08;PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机&#xff09;TIM输入捕获示例程序&…

基于EasyExcel的数据导入导出(复制可用)

目录 前言&#xff1a; 新建SpringBoot项目&#xff0c;引入下面的依赖 数据导入导出执行原理和思路&#xff1a; 用户端逻辑&#xff1a; 后台开发逻辑&#xff1a; 代码实现 下拉框策略 批注策略 数据读取监听 Excel工具类 创建导入数据模板类 创建数据导出模板 …

LC每日一题 2024/1/25 2859. 计算 K 置位下标对应元素的和

目录 题干 思路 代码 题干 思路 简单的位运算&#xff0c;就是寻找这个数对应的二进制中的1的个数是否与k相同&#xff0c;如果相同&#xff0c;就把这个数加到结果当中 可能涉及到的方法&#xff1a;Integer.bitCount() -->计算出二进制中包含的1的个数 代码 调用Java…

AI引爆算力需求,思腾推出支持大规模深度学习训练的高性能AI服务器

近日人工智能研究公司OpenAI公布了其大型语言模型的最新版本——GPT-4&#xff0c;可10秒钟做出一个网站&#xff0c;60秒做出一个游戏&#xff0c;参加了多种基准考试测试&#xff0c;它的得分高于88%的应试者&#xff1b;随后百度CEO李彦宏宣布正式推出大语言模型“文心一言”…

勒索袭击新方式,提防注册机中注入的勒索病毒!

1 事件概述 近期&#xff0c;用户反馈称自己在使用某款“注册机”软件时候&#xff0c;系统中文件被不行加密。通过对受害用户提供的线索和样本进 行综合分析研判&#xff0c;发现了一款借助破解类工具进行传播的新型勒索软件&#xff0c;其会通过向桌面释放勒索信与收款码图片…

mysql 基础(三)

一、多表设计 数据库设计范式 第一范式(确保每列保持原子性) 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值&#xff0c;就说明该数据库表满足了第一范式。第二范式就是要有主键&#xff0c;要求其他字段都依赖于主键。 没有主键就没有唯一性&…

用ChatGPT写申请文书写进常春藤联盟?

一年前&#xff0c;ChatGPT 的发布引发了教育工作者的恐慌。现在&#xff0c;各大学正值大学申请季&#xff0c;担心学生会利用人工智能工具伪造入学论文。但是&#xff0c;聊天机器人创作的论文足以骗过大学招生顾问吗&#xff1f; ChatGPT简介 ChatGPT&#xff0c;全称聊天生…

【格密码基础】基于LWE问题的密码系统

目录 一. 介绍 二. LWE密码方案简单介绍 三. LWE经典归约 四. LWE性质 五. LWE的鲁棒性 一. 介绍 在2005年&#xff0c;Regev基于LWE问题提出了一个新的公钥密码方案。该方案可实现语义安全&#xff08;semantic security&#xff09;&#xff0c;其中误差率&#xff08;…

【云原生】Docker的镜像创建

目录 1&#xff0e;基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改 ​编辑&#xff08;2&#xff09;然后将修改后的容器提交为新的镜像&#xff0c;需要使用该容器的 ID 号创建新镜像 实验 2&#xff0e;基于本地模板创建 3&am…

蓝凌OA sysUiExtend.do 任意文件上传漏洞复现

0x01 产品简介 蓝凌核心产品EKP平台定位为新一代数字化生态OA平台,数字化向纵深发展,正加速构建产业互联网,对企业协作能力提出更高要求,蓝凌新一代生态型OA平台能够支撑办公数字化、管理智能化、应用平台化、组织生态化,赋能大中型组织更高效的内外协作与管理,支撑商业…

[docker] Docker的数据卷、数据卷容器,容器互联

一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数据不会影响镜像&#xff0c;从而实现数据在宿主机与容…

81.网游逆向分析与插件开发-背包的获取-装备栏数据结构的逆向分析

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;自动化助手显示物品数据-CSDN博客 然后游戏中有弓箭&#xff0c;弓箭有数量&#xff0c;可以作为突破口&#xff0c;也可以使用物品id 获取弓的方式 获取弓箭的方式 然后搜索250 然后搜索出一个 然后…

Linux零碎点

目录 Linux基础命令 1、who&#xff1a; 2、hostname&#xff1a; 3、ifconfig&#xff1a; 4、pwd&#xff1a; 5、cd&#xff1a; 6、exit&#xff1a; 7、shutdown&#xff1a; 8、ls&#xff1a; 9、创建文件夹&#xff1a; 10、touch&#xff1a; 11、cp&#…

在百度云免费配置SSL证书 http改https操作

以下以在百度智能云上的操作为例&#xff0c;并不是给他打广告 1.购买域名 2.到域名管理处&#xff0c;解析网址&#xff0c;添加,*,www,指向服务器IP&#xff0c; 此时就可以访问网址&#xff1a;http://www.域名.cn 3.但是浏览器会报不安全&#xff0c;所以需要配置SSL证书…

acrobat调整pdf的页码和实际页码保持一致

Acrobat版本 具体操作 现在拿到pdf的结构如下&#xff1a; pdf页码实际页码1-10页无页码数11页第1页 操作&#xff0c;选择pdf第10页&#xff0c;右键点击 具体设置 最终效果