1. .装饰器的概念
· 装饰器是一种特殊类型的声明,它能够被附加到类的声明,方法,访问符,属性或参数上;
· 装饰器使用 @expression 这种形式,expression求值后必须为一个函数;
· 它会在运行时被调用,被装饰的声明信息做为参数传入。
· 装饰器执行时机是在代码编译时发生的(不是 TypeScript 编译,而是在 JavaScript 执行编译阶段)
启用装饰器特性,必须在命令行或 tsconfig.json 里启用 experimentalDecorators 编译器选项:
2. 装饰器语法
启用装饰器特性,必须在命令行或 tsconfig.json 里启用 experimentalDecorators 编译器选项:
// 在命令行中使用
tsc--target ES5--experimentalDecorators
// tsconfig.json 中开启:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
装饰器定义与应用举例:
// 装饰器定义
function sealed(target) {
// do something with "target" ...
}
// 或使用装饰器工厂函数
function color(value: string) { // 这是一个装饰器工厂
return function (target) { // 这是装饰器
// do something with "target" and "value"...
}
}
// 应用到一个声明上,例如:
@sealed @color let x: string;
// 或
@sealed
@color
let x: string
在 TypeScript 里,当多个装饰器应用在一个声明上时会进行如下步骤的操作:
· 由上至下依次对装饰器表达式求值。
· 求值的结果会被当作函数,由下至上依次调用。
多个装饰器应用在一个声明,举例:
// 多个装饰器应用在一个声明
function f() {
console.log("f(): evaluated");
return function (target, propertyKey: string) {
console.log("f(): called");
}
}
function g() {
console.log("g(): evaluated");
return function (target, propertyKey: string) {
console.log("g(): called");
}
}
class C {
@f() @g() method() { }
}
// f(): evaluated
// g(): evaluated
// g(): called
// f(): called
3. 类装饰器
类中不同声明上的装饰器将按以下规定的顺序应用:
· 有多个参数装饰器时:从最后一个参数依次向前执行。
· 方法和方法参数中,参数装饰器先执行。
· 方法和属性装饰器,谁在前面谁先执行。因为参数属于方法一部分,所以参数会挨着方法执行。
· 类装饰器总是最后执行。
类装饰器在类声明之前被声明(紧靠着类声明)。
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。
// 类装饰符实例
function Path(path: string) {
return function (target: Function) {
!target.prototype.$Meta && (target.prototype.$Meta = {})
target.prototype.$Meta.baseUrl = path;
};
}
@Path(‘/hello‘)
class HelloService {
[x: string]: any;
constructor() { }
}
console.log(HelloService.prototype.$Meta); // => { baseUrl: ‘/hello‘ }
let hello = new HelloService();
console.log(hello.$Meta) // => { baseUrl: ‘/hello‘ }
4. 方法装饰器
方法装饰器声明在一个方法的声明之前,可以用来监视,修改或者替换方法定义。
方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
· 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象;
· 成员的名字;
· 成员的属性描述符;
注意:如果代码输出目标版本小于ES5,属性描述符将会是 undefined,返回值会被忽略。 如果方法装饰器返回一个值,它会被用作方法的属性描述符。
方法装饰器,举例:
// 方法装饰符实例
function GET(alias: string) {
return function (target, methodName: string, descriptor: PropertyDescriptor) {
target._alias = alias;
}
}
class HelloService {
_alias: string;
constructor() { }
@GET("getMyName")
getUser() { }
}
let hello = new HelloService();
console.log(hello._alias); // => gtMyName
5. 访问装饰器
访问器装饰器声明在一个访问器的声明之前,可以用来监视,修改或替换一个访问器的定义。
访问装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
· 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象;
· 成员的名字;
· 成员的属性描述符;
注意:如果代码输出目标版本小于ES5,属性描述符将会是 undefined,返回值会被忽略。
如果访问装饰器返回一个值,它会被用作方法的属性描述符。
TypeScript 不允许同时装饰一个成员的get和set访问器;
一个成员的所有装饰的必须应用在文档顺序的第一个访问器上;因为在装饰器应用于一个属性描述 符时,它联 合了get和set访问器,而不是分开声明的。
访问装饰器,举例:
// 访问装饰器实例
function access(value: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
!target.$Meta && (target.$Meta = {})
target.$Meta[propertyKey] = `It‘s a ${value} method`
};
}
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@access(‘get‘)
get x() { return this._x; }
@access(‘set‘)
set y(y: number) { this._y = y; }
}
let point = new Point(1, 2);
console.log(point[‘$Meta‘]); // => { x: "It‘s a get method", y: "It‘s a set method" }
6. .属性装饰器
属性装饰器声明在一个属性声明之前。
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
· 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
· 成员的名字。
注意: 属性描述符不会做为参数传入属性装饰器,因为目前无法在定义一个原型对象的成员时描述一个实例属性,且无法监视或修改一个属性的初始化方法,因此,属性描述符只能用来监视类中是否声明了某个名字的属性。
属性装饰器,举例:
// 属性装饰符实例
function DefaultValue(value: string) {
return function (target: any, propertyName: string) {
target[propertyName] = value;
}
}
class Hello {
@DefaultValue("world")
greeting: string;
}
console.log(new Hello().greeting); // => world
7. 参数装饰器
参数装饰器声明在一个参数声明之前, 参数装饰器应用于类构造函数或方法声明。
参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
· 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象;
· 成员的名字;
· 参数在函数参数列表中的索引;
注意:
参数装饰器只能用来监视一个方法的参数是否被传入。
参数装饰器的返回值会被忽略。
参数装饰器,举例:
// 参数装饰器实例
function PathParam(paramName: string) {
return function (target, methodName: string, paramIndex: number) {
!target.$Meta && (target.$Meta = {});
target.$Meta[paramIndex] = paramName;
}
}
class HelloService {
constructor() { }
getUser(
@PathParam("the user‘s id")
userId: string
) { }
}
console.log((<any>HelloService).prototype.$Meta); // => { ‘0‘: "the user‘s id" }
原文:https://www.cnblogs.com/JosephWong/p/13684327.html