装饰器包括一下几种:

  • 属性装饰器
  • 方法装饰器
  • 访问器装饰器
  • 类装饰器
  • 参数装饰器

类中不同声明上的装饰器将按以下规定的顺序应用:

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

属性装饰器

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

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

不常规做法,


function isPassword(object: Object, propertyName: string) {
    let _propertyName = Symbol(propertyName)
    Object.defineProperty(object, propertyName, {
        set: function(val) {
            if (!/^[0-9a-zA-Z]{6,30}$/.test(val)) {
                throw new Error('密码格式错误');
            }
            this[_propertyName] = val;
            return this[_propertyName];
        },
        get: function() {
            return this[_propertyName];
        }
    })
}

function isPhone(object: Object, propertyName: string) {
    let _propertyName = Symbol(propertyName)
    Object.defineProperty(object, propertyName, {
        set: function(val) {
            if (!/^\d{11}$/.test(val)) {
                throw new Error('电话号码格式不对');
            }
            this[_propertyName] = val;
            return this[_propertyName];
        },
        get: function() {
            return this[_propertyName];
        }
    })
}

class Form {
    @isPhone phone: number;
    @isPassword passpowd: string

    constructor(passpowd: string, phone: number) {
        this.passpowd = passpowd;
        this.phone = phone;
    }

}

let data = new Form('acbd123', 123456789);

clipboard.png

方法装饰器

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

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

如果方法装饰器返回一个值,它会被用作方法的属性描述符。

示例:

function log(target: any, propertyKey: string, descriptor: any) {
    var originalMethod = descriptor.value;
  
    descriptor.value =  function (...args: any[]) {
        var result = originalMethod.apply(this, args);
        var r = JSON.stringify(result);
        console.log('返回值:' + r);
        return result;
    }
  
    return descriptor;
}

 class Person {
    name: string;
    age: number;
    phone: number;

    constructor(name: string, age: number, phone: number) {
        this.name = name;
        this.age = age;
        this.phone = phone;
    }

    @log
    getGrowUp(year) {
        this.age += year;
        return this.age;
    }

}


const men = new Person('张三', 18, 1234567890);
men.getGrowUp(5);

clipboard.png

访问器装饰器

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

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

示例:

class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }

    @configurable(false)
    get x() { return this._x; }

    @configurable(false)
    get y() { return this._y; }
}

function configurable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.configurable = value;
    };
}

const point = new Point(50, 50);
point.x = 60;
console.log(point.x)

clipboard.png

类装饰器

类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。

如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。

注意 如果你要返回一个新的构造函数,你必须注意处理好原来的原型链。 在运行时的装饰器调用逻辑中 不会为你做这些。

示例:

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

依赖注入示例
来源:https://blog.csdn.net/HaoDaWa...

//ioc容器
let classPool:Array<Function> = [];

//注册该类进入容器
function Injectable(){
    return (_constructor:Function) => {
        let paramTypes:Array<Function> = Reflect.getMetadata('design:paramtypes',_constructor)
        //已注册
        if(classPool.indexOf(_constructor) != -1) return;
        for(let val of paramTypes){
            if(val === _constructor) throw new Error('不能依赖自己')
            else if(classPool.indexOf(val) == -1) throw new Error(`${val}没有被注册`)
        }
        //注册
        classPool.push(_constructor);
    }
}

//实例化工厂
function classFactory<T>(_constructor:{new(...args:Array<any>):T}):T{
    let paramTypes:Array<Function> = Reflect.getMetadata('design:paramtypes',_constructor)
    //参数实例化
    let paramInstance = paramTypes.map((val:Function) => {
        //依赖的类必须全部进行注册
        if(classPool.indexOf(val) == -1) throw new Error(`${val}没有被注册`)
        //参数还有依赖
        else if(val.length){
            return classFactory(val as any);
        }
        //没有依赖直接创建实例
        else{
            return new (val as any)();
        }
    })
    return new _constructor(...paramInstance);
}


@Injectable()
class C{
    constructor(){}

    sayHello(){
        console.log("hello")
    }
}

@Injectable()
class B{
    constructor(private c:C){

    }

    sayHello(){
        this.c.sayHello();
    }
}

@Injectable()
class A{
    constructor(private b:B){
        
    }    

    say() {
        this.b.sayHello();
    }
}

//产生实例
const a:A = classFactory(A);
a.say()



参数装饰器

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

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  • 成员的名字。
  • 参数在函数参数列表中的索引。

参数装饰器通常需要配合方法装饰器和元数据

class Person {
  type: string;
  name: string;

  @validate
  login(@phone phone, @password password) {
    // 数据库操作...
    return {
      name: 'Ryan',
      phone: phone,
      sex: 1
    }
  }
}


function validate(target, propertyKey, descriptor) {
  const fun = descriptor.value;
  descriptor.value = function() {
    Validator(propertyKey, target, arguments);
    return fun.apply(this, arguments);
  };
}


function phone(target, propertyKey, index) {
  Reflect.defineMetadata(propertyKey, index, target, 'phone');
}

function password(target, propertyKey, index) {
  Reflect.defineMetadata(propertyKey, index, target, 'password');
}

function Validator(propertyKey, target, data) {
  let rules = [
    {
      type: 'phone', 
      hasError: (val) => !/^\d{11}$/.test(val),
      message: '手机号码的格式不对'
    },
    {
      type: 'password', 
      hasError: (val) => !/^\w{6,36}$/.test(val),
      message: '密码的格式不对'
    }
  ];

  for (let item of rules) {
    let key = Reflect.getMetadata(propertyKey, target, item.type);
    if (data.hasOwnProperty(key)) {
      if (item.hasError(data[key])) {
        throw new BadRequestException(item.message);
      } 
    }
  }
  
}

const p = new Person();
p.login(183206650110, 'aa1213456');

Ryan
91 声望3 粉丝