TypeScript裝飾器

裝飾器是一種特殊類型的聲明,它可以用在類聲明、方法、屬性或者參數(shù)上。顧名思義,它是用來給附著的主體進(jìn)行裝飾,添加額外的行為。
裝飾器使用@expression這種形式,expression求值后必須為一個函數(shù),它會在運(yùn)行時被調(diào)用,被裝飾的聲明信息做為參數(shù)傳入。

方法裝飾器

方法裝飾器聲明在一個方法的聲明之前(緊靠著方法聲明)。 它會被應(yīng)用到方法的 屬性描述符上,可以用來監(jiān)視,修改或者替換方法定義。 方法裝飾器不能用在聲明文件( .d.ts),重載或者任何外部上下文(比如declare的類)中。
方法裝飾器表達(dá)式會在運(yùn)行時當(dāng)作函數(shù)被調(diào)用,傳入下列3個參數(shù):

  • 對于靜態(tài)成員來說是類的構(gòu)造函數(shù),對于實(shí)例成員是類的原型對象。
  • 成員的名字。
  • 成員的屬性描述符。
 class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }

    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting;
    }
}

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

這里的@enumerable(false)
是一個裝飾器工廠。 當(dāng)裝飾器 @enumerable(false)
被調(diào)用時,它會修改屬性描述符的enumerable
屬性。

類裝飾器

類裝飾器在類聲明之前被聲明(緊靠著類聲明)。 類裝飾器應(yīng)用于類構(gòu)造函數(shù),可以用來監(jiān)視,修改或替換類定義。 類裝飾器不能用在聲明文件中( .d.ts),也不能用在任何外部上下文中(比如declare的類)。
類裝飾器表達(dá)式會在運(yùn)行時當(dāng)作函數(shù)被調(diào)用,類的構(gòu)造函數(shù)作為其唯一的參數(shù)。
如果類裝飾器返回一個值,它會使用提供的構(gòu)造函數(shù)來替換類的聲明。
注意 如果你要返回一個新的構(gòu)造函數(shù),你必須注意處理好原來的原型鏈。 在運(yùn)行時的裝飾器調(diào)用邏輯中 不會為你做這些。
下面是使用類裝飾器(@sealed)的例子,應(yīng)用在Greeter類:

@sealed
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

我們可以這樣定義@sealed裝飾器:

function sealed(constructor: Function) {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

當(dāng)@sealed被執(zhí)行的時候,它將密封此類的構(gòu)造函數(shù)和原型。(注:參見Object.seal)

Angular中大量使用了類裝飾器,@Directive, @Injectable

@Component(
    {
        selector:"loading",
        template:"loading.html"
    }
)
class Loading{

}

參數(shù)裝飾器

參數(shù)裝飾器聲明在一個參數(shù)聲明之前(緊靠著參數(shù)聲明)。 參數(shù)裝飾器應(yīng)用于類構(gòu)造函數(shù)或方法聲明。

class Greeter {
    greeting: string;

    constructor(message: string) {
        this.greeting = message;
    }

    @validate
    greet(@required name: string) {
        return "Hello " + name + ", " + this.greeting;
    }
}

然后我們使用下面的函數(shù)定義 @required 和 @validate 裝飾器:

import "reflect-metadata";

const requiredMetadataKey = Symbol("required");

function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
    let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
    existingRequiredParameters.push(parameterIndex);
    Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}

function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {
    let method = descriptor.value;
    descriptor.value = function () {
        let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
        if (requiredParameters) {
            for (let parameterIndex of requiredParameters) {
                if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
                    throw new Error("Missing required argument.");
                }
            }
        }

        return method.apply(this, arguments);
    }
}

@required裝飾器添加了元數(shù)據(jù)實(shí)體把參數(shù)標(biāo)記為必需的。 @validate裝飾器把greet方法包裹在一個函數(shù)里在調(diào)用原先的函數(shù)前驗(yàn)證函數(shù)參數(shù)。

屬性裝飾器

和其他類似

裝飾器組合

@decoratorA
@decoratorB
functionA

或者 在同一行
@decoratorA @decoratorB functionA

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容