定义
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上,是一种在不改变原类和使用继承的情况下,动态的扩展对象功能。
装饰器使用@expression
形式,其中expression
必须评估为一个函数,该函数将在运行时调用,并带有有关装饰声明的信息。
前置操作
// tsconfig.json
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
使用
类装饰
类装饰器会把Class A
的构造函数传入你的watche
r函数当做第一个参数
const watcher: ClassDecorator = (target) => {
target.prototype.age = 18
target.prototype.getName = ():string=>{
return 'hello'
}
}
@watcher
class A {
constructor() {
}
}
const a = new A()
console.log((a as any).age); // 18
console.log((a as any).getName()); //hello
装饰器工厂
如果想要传递参数,使装饰器变成类似工厂函数,只需要在装饰器函数内部再返回一个函数即可。
const watcher = (name: string): ClassDecorator => {
return (target) => {
target.prototype.age = 18
target.prototype.getName = (): string => {
return name
}
}
}
@watcher('hello data')
class A {
constructor() {
}
}
const a = new A()
console.log((a as any).age); // 18
console.log((a as any).getName()); // hello data
装饰器组合
可以给一个类使用多个装饰器
const watcher = (name: string): ClassDecorator => {
return (target) => {
target.prototype.age = 18
target.prototype.getName = (): string => {
return name
}
}
}
const addAge = (age:number):ClassDecorator => {
return (target) =>{
target.prototype.addAge = (): number => {
return age+1
}
}
}
@watcher('hello data') @addAge(20)
class A {
constructor() {
}
}
const a = new A()
console.log((a as any).age);
console.log((a as any).getName());
console.log((a as any).addAge());
方法/属性装饰器
装饰器参数为:
- target:对象的原型:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- propertyKey:方法的名称
- descriptor:方法的属性描述符
这三个属性实际就是Object.defineProperty
的三个参数,如果是类的属性,则没有传递第三个参数
const met: MethodDecorator = (...args) => {
console.log(args)
}
class A {
constructor() {
}
@met
getName(): string {
return 'hello'
}
}
const xx = new A()
// 声明装饰器修饰方法/属性
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.writable = false;
};
function property(target: any, propertyKey: string) {
// 修改属性
target[propertyKey] = '11223'
}
class Person {
@property
name: string;
constructor() {
}
@method
say() {
return 'instance method';
}
}
const xmz = new Person();
// 修改实例方法say
xmz.say = () => {
return '5566' //由于 descriptor.writable = false; 所以此处修改不生效
}
console.log(xmz.name)
console.log(xmz.say()) // nstance method
参数装饰
装饰器参数为:
- target:当前对象的原型
- propertyKey:参数的名称
- index:参数数组中的位置
const init: ParameterDecorator = (...args)=>{
console.log(args)
}
class A {
constructor() {
}
getName(@init name: string = 'hello') {
console.log(name) // [ {}, 'getName', 0 ]
}
}
元数据
import data from './data.json'
import 'reflect-metadata'
const Base = (base: string) => {
return (target) => {
target.prototype.base = base
}
}
const GetData = (url: string) => {
console.log('getData run')
const fn: MethodDecorator = (target: any, key, descriptor: PropertyDescriptor) => {
const prop = Reflect.getMetadata('key', target)
console.log(prop, 'prop')
descriptor.value(prop ? data[prop] : data)
}
return fn;
}
const Result = () => {
console.log('result run')
const fn: ParameterDecorator = (target: any, key, index) => {
Reflect.defineMetadata('key', 'data', target)
}
return fn
}
@Base('/api')
class Http {
fileName: string
constructor(name) {
this.fileName = name
}
@GetData('json')
getList(@Result() data: any) {
console.log(data)
}
}
const http = new Http('orange')