ts装饰器

138 阅读2分钟

装饰器:(Decorator)

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上。 装饰器使用@teacher这种形式,teacher必须是一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。 根据被装饰的对象不同,装饰器分为以下几类:

类装饰器:

//定义类装饰器
function teacher(target: Function) {
   console.log(target)
}

//语法糖使用
@teacher
class Person {}

//实质上的调用
class Person {}
teacher(Person);

控制台输出

[Function teacher]

只有一个参数:target为装饰类的构造函数。

方法装饰器:

function teacher(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log('target ', target);
    console.log('propertyKey ', propertyKey);
    console.log('descriptor ', descriptor);
}
//语法糖使用
class Person {
    @teacher
     demo() {
        console.log('demo');
    }
}
//实质上的调用
teacher(Person.prototype/Person,'domo',方法的描述符)

控制台输出

target  { demo: [Function (anonymous)] } 
// target  [Function: Person] { demo: [Function (anonymous)] }  静态方法输出
propertyKey  demo
descriptor  {
  value: [Function (anonymous)],
  writable: true,
  enumerable: true,
  configurable: true
}

propertyKey  demo
descriptor  {
  value: [Function (anonymous)],
  writable: true,
  enumerable: true,
  configurable: true
}

3个参数:

  1. 类的原型对象,如果是静态方法则为类的构造函数
  2. 方法名称
  3. 方法的属性描述符

属性装饰器:

属性装饰器多用在属性依赖注入上面。属性装饰器接收两个参数:

  1. 类的原型对象,如果是静态方法则为类的构造函数
  2. 属性名
function demo(value: string) {
	return function(target: any, propertyKey: string) {
		target[propertyKey] = value;
	}
}
class Demo {
    @demo('haha') name?: string;
}

const d = new Demo();
console.log(d.name);

函数参数装饰器:

参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 参数的名字。
  3. 参数在函数参数列表中的索引。
function PathParam(paramDesc: string) {
  return function (target: any, paramName: string, paramIndex: number) {
  !target.$meta && (target.$meta = {});
  target.$meta[paramIndex] = paramDesc; 
  }
} 
class Demo { 
constructor() { } 
getUser( @PathParam("userId") userId: string) { } 
}
console.log((<any>Demo).prototype.$meta);

工厂模式

装饰器工厂

装饰器工厂也是一个函数,只不过它的返回值是一个装饰器,装饰器工厂在使用时可以传参,普通装饰器不可以。例:

function event(eventName: string) {
    return function(target: any) {
        // 获取到当前eventName和被装饰对象进行操作
    }
}

使用

@event('chifan')
Class  person {

}

装饰器执行顺序:

  1. 装饰器工厂需要先求值,再装饰,求值顺序是由上到下
  2. 装饰器可以直接求值,装饰顺序是由下到上

装饰器与继承的区别

装饰器可叠加使用