文章目录
提示:
1.前提确保你的 TypeScript 配置启用了装饰器:
确保你的 TypeScript 配置启用了装饰器:
在 tsconfig.json 中添加:
experimentalDecorators: true = 让 TypeScript 理解 @装饰器 语法
emitDecoratorMetadata: true = 为装饰器添加额外的类型信息(主要用于框架)
"compilerOptions": {
/*
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
这两个作用:
experimentalDecorators: true = 让 TypeScript 理解 @装饰器 语法
emitDecoratorMetadata: true = 为装饰器添加额外的类型信息(主要用于框架)
*/
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

装饰器(特殊函数)
一、简介
二、类装饰器


3.关于返回值
//关于返回值
function Demo(target: Function){
// return class {
// test(){
// console.log(200);
// console.log(400);
// console.log(300);
// }
// }
}
@Demo
class Person{
test(){
console.log(100);
}
}
console.log(Person);


4.关于构造类型

/*
new 表示该类型是可以用new操作符来调用
...args 表示构造器可以接受【任意数量】的参数
any[] 表示构造器可以接受【任意类型】的参数
{} 表示返回类型是对象(非null,非undefined的对象)
*/
type Constructor = new (...args:any[]) =>{}
//需求fn是一个函数,调用fn并返回结果
function test (fn:Function){}
class Person{}
test(Person)


5.替换被装饰的类
装饰器里面return即可

//需求:设计一个LogTime装饰器,可以给实例填加一个属性,
// 用于记录实例对象的创建时间,再添加一个方法,用于获取创建时间
//还有更多功能
type Constructor =new (...args:any[])=>{};
//为类添加接口声明,要不然console.log(p1.getCreateTime());报错说Person上没有这个方法
interface Person{
getCreateTime():void;
// createTime:Date;
// getCreateTime():string;
}
//装饰器
function LogTime<T extends Constructor>(target:T){
return class extends target{
createTime:Date;
constructor(...args:any[]){
super(...args);
this.createTime=new Date();
}
getCreateTime(){
return `创建时间是:${this.createTime}`
}
};
}
@LogTime
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
Speak() {
console.log(`My name is ${this.name}, I am ${this.age} years old.`);
}
}
const p1=new Person("Alice", 30);
console.log(p1);
console.log(p1.getCreateTime());
三、装饰器工厂


四、装饰器组合




五、属性装饰器
区别与类装饰器







六、方法装饰器




参数说明
/*
参数说明:
target:对于静态方法来说值是类,对于实例方法来说值是原型对象
propertyKey;方法的名称
descriptor:方法的描述对象,其中value属性是被装饰的方法
*/
function Demo(target:object,propertyKey:string,descriptor:PropertyDescriptor){
console.log(target)
console.log(propertyKey)
console.log(descriptor)
}
class Person{
constructor(
public name:string,
public age:number
){}
//Demo装饰实例的方法
@Demo speak(){
console.log(`你好,我的名字是:${this.name},我的年龄${this.age}`)
}
//Demo装饰静态的方法
@Demo static isAdult(age:number){
return age >=18
}
}
// ********** 调用示例 **********
// 1. 实例方法:必须先创建实例,通过实例调用
const person1 = new Person("张三", 20);
person1.speak(); // 输出:你好,我的名字是:张三,我的年龄20
// 错误写法:直接用类调用实例方法(会报错)
// Person.speak(); // ❌ Property 'speak' does not exist on type 'typeof Person'
// 2. 静态方法:直接通过类调用,不需要创建实例
console.log(Person.isAdult(20)); // 输出:true
console.log(Person.isAdult(17)); // 输出:false
// 错误写法:通过实例调用静态方法(TS会提示,JS中虽能执行但不推荐)
// person1.isAdult(20); // ❌ Property 'isAdult' does not exist on type 'Person'
打印日志的装饰器
//打印日志的装饰器
// 可以执行之前走一个逻辑,speak执行之后走一个逻辑
function Logger(target: object, propertyKey: string, descriptor: PropertyDescriptor) {//内置的类型PropertyDescriptor(属性的描述器)
//存储原始方法
const originnal = descriptor.value
//替换原始方法
descriptor.value = function (...args: any[]) {
console.log(`${propertyKey}开始执行......`)
const result = originnal.call(this, ...args)//这一行代码是用来执行原始函数,如果这一行写成
/*
originnal() 这样会把this搞丢,所以要写成original.call(this,)传参数
*/
/* js原始知识:面试题
const result = originnal.call(this, ...args)
return originnal.apply(this,args)
call和apply区别:都能修改函数this,但是他俩第二个参数不同,
对于call得一个一个传进去,而对于apply需要传递一个数组
*/
console.log(`${propertyKey}执行完毕......`)
return result//speak方法有返回值
}
}
//装饰器Validate
function Validata(maxValue: number) {
return function (target: object, propertyKey: string, descriptor: PropertyDescriptor) {
//保存原始方法
const originnal = descriptor.value;
//替换原始方法
descriptor.value = function (...args: any[]) {
//自定义的验证逻辑
if (args[0] > maxValue) {
throw new Error('年龄非法!')
}
//如果所有参数都符合要求,则调用原始方法
return originnal.apply(this, args)
}
}
}
class Person {
constructor(
public name: string,
public age: number
) { }
//方法装饰器
// str:string
@Logger speak() {
console.log(`你好,我的名字是:${this.name},我的年龄${this.age}`)
}
@Validata(120)
static isAdult(age: number) {
return age >= 18
}
}
const p1 = new Person('tom', 19)
console.log(p1.speak)
js原始知识:面试题
const result = originnal.call(this, …args)
return originnal.apply(this,args)
call和apply区别:都能修改函数this,但是他俩第二个参数不同,
对于call得一个一个传进去,而对于apply需要传递一个数组
七、访问器装饰器




/*
参数说明:
target:
1.对于实例访问器起来说值是【所属类的原型对象】
2.对于静态访问器来说值是【所属类】
propertyKey:访问器的名称
descriptor:描述对象
*/
function Demo(target:object,propertyKey:string,descriptor:PropertyDescriptor){
// console.log(target)
// console.log(propertyKey)
console.log(descriptor)
}
class Person{
@Demo//实例访问器
get address(){
return'北京科技园'
}
@Demo//静态访问器
static get country(){
return '中国'
}
}

参数说明:
/*
参数说明:
target:
1.对于实例访问器起来说值是【所属类的原型对象】
2.对于静态访问器来说值是【所属类】
propertyKey:访问器的名称
descriptor:描述对象
*/
function Demo(target:object,propertyKey:string,descriptor:PropertyDescriptor){
// console.log(target)
// console.log(propertyKey)
console.log(descriptor)
}
class Person{
@Demo//实例访问器
get address(){
return'北京科技园'
}
@Demo//静态访问器
static get country(){
return '中国'
}
}
实例说明
//访问器(set,get),装饰器工厂
function RangeValidate(min:number,max:number){
return function(target:object,propertyKey:string,descriptor:PropertyDescriptor){
//保存原始的setter方法,以便在后续调用中使用
const originalSetter= descriptor.set;
//重写setter方法,加入范围验证逻辑
descriptor.set = function (value:number){
//检查设置的值是否在指定的最小值和最大值之间
if(value<min||value>max){
//如果值不在范围内,抛出错误
throw new Error (`${propertyKey}的值应该在${min}到${max}之间`)
}
//如果值不在范围内,且原始setter方法存在,则调用原始的setter方法
if (originalSetter){
originalSetter.call(this,value);
}
}
}
}
class Weather{
private _temp:number;//温度
constructor(_temp:number){
this._temp=_temp
}
//设置温度范围在-50到50之间
@RangeValidate(-50,50)//范围验证,装饰器工厂
set temp(value){
this._temp=value;
}
get temp(){
return this._temp;
}
}
const w1=new Weather(25)
console.log(w1.temp)
// console.log(w1)
八、参数装饰器


/*
参数说明:
target:
1.如果修饰的是【实例方法】的参数,target是类的【原型对象】
2.如果修饰的是【静态方法】的参数,target是【类】
propertyKey:参数所在的方法的名称
paranameterIndex:参数在函数列表中的索引,从0开始
*/
function Demo(target: object, propertyKey: string, paranameterIndex: number) {
console.log(target)
console.log(propertyKey)
console.log(paranameterIndex)
}
//类定义
class Person {
constructor(public name: string) { }
speak(@Demo message1: any, message2: any) {
console.log(`${this.name}想对说:${message1},${message2}`)
}
}
1789

被折叠的 条评论
为什么被折叠?



