裝飾器的一些用法

裝飾器包括一下幾種:數據庫

  • 屬性裝飾器
  • 方法裝飾器
  • 訪問器裝飾器
  • 類裝飾器
  • 參數裝飾器

類中不一樣聲明上的裝飾器將按如下規定的順序應用:app

參數裝飾器,而後依次是方法裝飾器,訪問符裝飾器,或屬性裝飾器應用到每一個實例成員。
參數裝飾器,而後依次是方法裝飾器,訪問符裝飾器,或屬性裝飾器應用到每一個靜態成員。
參數裝飾器應用到構造函數。
類裝飾器應用到類。ide

屬性裝飾器

屬性裝飾器表達式會在運行時看成函數被調用,傳入下列2個參數:函數

  • 對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象。
  • 成員的名字。

不常規作法,this

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個參數:spa

  • 對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象。
  • 成員的名字。
  • 成員的屬性描述符。

若是方法裝飾器返回一個值,它會被用做方法的屬性描述符。.net

示例:code

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個參數:orm

  • 對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象。
  • 成員的名字。
  • 成員的屬性描述符。

示例:對象

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');
相關文章
相關標籤/搜索