裝飾器是一種特殊類型的聲明,它可以用在類聲明、方法、屬性或者參數(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