编辑
2023-03-26
TypeScript
0
请注意,本文编写于 531 天前,最后修改于 515 天前,其中某些信息可能已经过时。

目录

配置
装饰器定义
语法:
Eg
规则
多个装饰器对同一个类使用
类中其他顺序
装饰器的类型
类装饰器
说明
用途
方法装饰器
说明
属性描述符
使用

配置

tsconfig.json中开启对应配置从而让ts支持装饰器

"experimentalDecorators": true,

装饰器定义

装饰器是一种特殊类型声明, 它能够被附加到类声明、方法、属性或者参数上, 可以修改类的行为,
通俗的讲装饰器就是一个方法,可以注入到类,方法,属性参数上来扩展类,属性,方法,参数功能
装饰器求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入

常见的装饰器:属性装饰器,方法装饰器,参数装饰器

语法:

普通修饰器(无法传参)、装饰器工厂(可以传参)

Eg

  • 普通修饰器
ts
function nameClass(params:any){ console.log("装饰器",params) } @nameClass class people { constructor(){ } }
  • 装饰器工厂 其返回值是一个函数
ts
function nameClass(params:any){ return (target:any)=>{ console.log("装饰器",params,target) } } @nameClass(2) class people { constructor(){ } }

规则

多个装饰器对同一个类使用

由上至下依次对装饰器表达式求值
求值的结果会被当作函数,由下至上依次调用

  • EG
ts
function nameClass(params:any){ console.log("装饰器1") return (target:any)=>{ console.log("装饰器1",params,target) } } function ageClass(params:any){ console.log("装饰器2") return (target:any)=>{ console.log("装饰器2",params,target) } } @nameClass(1) @ageClass(2) class people { constructor(){ } }
  • RESULT
ts
装饰器1 装饰器2 装饰器2 2 class people { constructor() { } } 装饰器1 1 class people { constructor() { } }

类中其他顺序

装饰器求值(即工厂函数) 类中不同声明上的装饰器将按以下顺序应用:

  • 参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个实例成员
  • 参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个静态成员
  • 参数装饰器应用到构造函数
  • 类装饰器应用到类

装饰器的类型

类装饰器

说明

应用于类构造函数,其参数是类的构造函数

用途

  • 在类的构造函数的原型上添加属性
ts
// 类装饰器 function addName(constructor:new() => any){ constructor.prototype.name = "xm" } @addName class ClassD {} //使用接口,声明一个的类名相同的接口,声明合并;不然报错ClassD上没有name interface ClassD{ name:string } const d = new ClassD() console.log(d.name) //xm
  • 重写装饰的类的构造函数
ts
function classDecorator<T extends new(...args:any[])=>{}>(target:T) { return class extends target { public newProperety = "new property" public hello = "hello" } } @ classDecorator class Greeter { public property = "property" public hello:string constructor(m:string) { this.hello = m } } const targets = new Greeter("hello world") console.log(targets) // 打印结果 // Greeter {property: 'property', hello: 'hello', newProperety: 'new property'} // hello: "hello" // newProperety: "new property" // property: "property" // [[Prototype]]: Greeter // ... // 验证是否重写类的构造函数 function classConstrustor(target:any):any { return class target { public names = "xm" public age = 18 } } @ classConstrustor class people { public hobby = "food" public sex = 0 constructor(m:number) { this.sex = m } } const targets = new people(0) console.log(targets) // 打印结果 // 此处装饰器返回的类重写了类prople的构造函数 // 原本的hobby sex都被舍弃 // target {names: 'xm', age: 18} // age: 18 // names: "xm" // [[Prototype]]: Object // ...

方法装饰器

说明

它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义

属性描述符

通过Object.defineProperty方法设置
最低为ES5版本支持Object.defineProperty方法

  • 语法
Object.defineProperty(target,name,{ value:"xm",//属性值 writable:false,//是否可写 configurable:false,//是否可配置 enumerable:true,//是否可枚举 })

target:要设置的对象 name:对象的属性名 第三个参数:

  • writable: boolean,是否可写,设置为true后再次赋值无法更改
  • configurable: boolean,是否允许配置,设置为false后,无法再次声明对象
  • enumerable: boolean,是否允许枚举,设置为true后,for循环遍历对象属性名可以取到

Eg

ts
// 属性描述符 interface ObjWithAnyKeys { [key:string]:any } let obj2:ObjWithAnyKeys = {} //使用属性修饰符 Object.defineProperty(obj2,"name",{ value:"xm",//属性值 writable:false,//是否可写 configurable:false,//是否可配置 enumerable:true,//是否可枚举 }) // console.log(obj2.name)// xm //当writeable设置为false时 obj2.name = "ls"//报错,无法分配只读属性name console.log(obj2.name) //当writeable设置为true时 obj2.name = "ls" console.log(obj2.name) // ls // 当configurable设置为false时,不允许重定义name Cannot redefine property: name Object.defineProperty(obj2,"name",{ value:"xm",//属性值 writable:false,//是否可写 configurable:true,//是否可配置 enumerable:true,//是否可枚举 }) // 当enumerable设置为true时 for(let keys in obj2){ console.log(keys) //name }

使用

方法装饰器在运行时传入下列3个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 成员的名字
  • 成员的属性描述符

1、对于类的实例成员

ts
// 此处设置属性为不可枚举的 function enumerable(types:boolean) { return (target:any,propertName:string,descriptor: PropertyDescriptor) => { console.log(target) console.log(target===ClassFN.prototype)// true 对于类的实例成员 target为类的实例对象 descriptor.enumerable = types } } class ClassFN { constructor( public age = 18) { } @enumerable(false) //改为true后 public getAge() { return this.age } } const classFn = new ClassFN(22) for (let keys in classFn){ console.log(keys) //age ,更改后结果为age getAge } // 运行结果 // [LOG]: ClassFN: {} // [LOG]: true // [LOG]: "age"

2、对于类的私有成员

ts
// 此处设置属性为不可枚举的 function enumerable(types:boolean) { return (target:any,propertName:string,descriptor: PropertyDescriptor) => { console.log(target) console.log(target===ClassFN)// true 对于类的私有成员,为类本身 descriptor.enumerable = types } } class ClassFN { public age = 18 constructor( ) { } @enumerable(false) //改为true后 static getAge(){ return ClassFN.getAge } } const classFn = new ClassFN() for (let keys in classFn){ console.log(keys) //age ,更改后结果为age getAge }

本文作者:RKLS

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!