介绍
详细的关于ts中装饰器的使用和语法可以参考 ts官网中decorator这一章节,或者阮一峰的ts教程的decorator章节这里这是个人对装饰器的理解和使用。
装饰器是一种特殊类型的声明,使用
@expression
这种形式,其中expression
求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息作为参数传入。
装饰器是一种类 class
相关的语法,所以只能用在 class
里面,个人理解装饰器相当于在外层加入了一层拦截作用
下面针对不同装饰器举例说明
类装饰器
类装饰器在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义
类装饰器表达式会在运行时当做函数被调用,类的构造函数函数作为其唯一的参数
下面看一个类装饰器的例子
// 装饰器
function myDecorator(constructor: Function) {
Object.defineProperty(constructor.prototype, 'sayName', {
value: function() {
return 'myDecorator sayName'
}
})
}
@myDecorator
class Person {
public name: string
constructor(name: string) {
this.name = name
}
sayName() {
return this.name
}
}
const p1 = new Person('yy')
console.log(p1.sayName()) // myDecorator sayName
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
下面是一个构造函数重载的例子,这里的类装饰器就是返回了一个值(返回一个继承后的原构造函数)
// 装饰器
function myDecorator<T extends {new(...args: any[]): {}}>(constructor: T) {
return class extends constructor {
name: string = 'new name'
age: number = 17
sayName() {
return this.name + this.age
}
}
}
@myDecorator
class Person {
public name: string
constructor(name: string) {
this.name = name
}
sayName() {
return this.name
}
}
const p1 = new Person('yy')
console.log(p1.sayName()) // new name17
console.log(p1) // {name: 'new name' age: 17}
// 注意,虽然 p1 有 age 属性,但是不能通过 p1.age 来访问
方法装饰器
方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。它会被应用到方法的属性描述符上用来监视,修改或替换方法定义
方法装饰器表达式在运行时当做函数被调用,传入三个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 成员的名字
- 成员的属性描述符
如果方法装饰器返回一个值,它会被用作方法的属性描述符
// 装饰器
function myDecorator(value: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(target, propertyKey) // {} sayName
descriptor.value = function() {
return 'decorator ' + value
}
}
}
class Person {
public name: string
constructor(msg: string) {
this.name = msg
}
@myDecorator('hellowee')
sayName() {
return this.name
}
}
const p1 = new Person('yy')
console.log(p1.sayName()) // decorator hellowee
再看一个关于 log
的装饰器,可以起到输出日志的作用
// 装饰器
function log(target: any, prop: string, descriptor: PropertyDescriptor) {
let oldValue = descriptor.value
descriptor.value = function() {
console.log('log--> sum')
return oldValue.apply(this, arguments)
}
}
class Math2 {
@log
sum(a: number, b: number): number {
return a + b
}
}
const math = new Math2()
console.log(math.sum(1, 2))
// log--> sum
// 3