Appearance
基础篇-装饰器
什么是装饰器
装饰器是一种特殊类型的声明,它可以被附加到类声明,方法,属性或参数上,可以修改类的行为。通俗的讲,装饰器就是一个方法,可以注入到类、方法、属性、参数上来扩展类、方法、属性、参数的功能。
装饰器调用顺序:属性装饰器>方法参数装饰器>方法装饰器>静态属性装饰器>静态方法装饰器>类装饰器
定义:相同装饰器按右边>左边 ,下面>上面
执行:相同装饰器按左边>右边 ,上面>下面
以下两种风格均是合法的
ts
@f @g x
ts
@f
@g
x
在 TypeScript 中装饰器还属于实验性语法,所以要想使用必须在配置文件中 tsconfig.json 编译选项中开启
ts
{
"compilerOptions": {
"experimentalDecorators": true
}
}
普通装饰器
ts
/**
* 装饰器
* target:代表当前修饰的类
*/
function logClass(target: any) {
console.log(target);
target.prototype.data = 'dataChange';
}
@logClass
class Operator {
data: string | undefined;
constructor() {}
getData(): any {
console.log('data:', this.data);
}
}
const newOperator = new Operator();
newOperator.getData(); // dataChange
console.log(newOperator.data); // dataChange
装饰器工厂
ts
/**
* params:类装饰器传入的参数
* target:当前修饰的类
*/
function logClass1(params: string) {
console.log('装饰器1');
return function (target: any) {
console.log('params1:', params);
console.log(target);
target.prototype.data = params;
};
}
function logClass2(params: string) {
console.log('装饰器2');
return function (target: any) {
console.log('params2:', params);
console.log(target);
target.prototype.name = params;
};
}
@logClass1('hello')
@logClass2('world')
class TestClass {
name: string | undefined;
data: string | undefined;
constructor() {}
getData(): any {
console.log('name:', this.name);
console.log('data:', this.data);
}
}
控制台输出顺序
ts
/* 装饰器1
装饰器2
params2: world
TestClass() {}
params1: hello
TestClass() { } */
不同类型的装饰器
装饰器执行顺序:属性装饰器>方法装饰器>参数装饰器>类装饰器 如果有多个同类型的装饰器,则执行顺序是从后到前执行。
ts
// 装饰器调用顺序
// 属性装饰器>方法参数装饰器>方法装饰器>静态属性装饰器>静态方法装饰器>类装饰器
// 定义:相同装饰器按右边>左边 ,下面>上面
// 执行:相同装饰器按左边>右边 ,上面>下面
/**
* 属性装饰器
* @param targetPrototype 构造函数的原型
* @param propName 属性名称
*/
function propDecorator1(targetPrototype: any, propName: string) {
console.log('属性装饰器1:', targetPrototype, propName);
}
function propDecorator2(params: string) {
console.log('属性装饰器2 before:', params);
return function (targetPrototype: any, propName: string) {
// targetPrototype[propName]是在原型链上查找实例属性,永远为undefined
console.log(
'属性装饰器2:',
targetPrototype,
propName,
targetPrototype[propName],
);
targetPrototype[propName] = '会在原型上面添加该属性并赋值,不是实例对象';
};
}
function propDecorator3(params: string) {
console.log('属性装饰器3 before:', params);
return function (targetPrototype: any, propName: string) {
console.log('属性装饰器3:', targetPrototype, propName);
};
}
/**
* 方法装饰器
* @param targetPrototype 构造函数的原型
* @param methodName 方法名称
* @param descr 方法的描述
*/
function methodDecorator1(
targetPrototype: any,
methodName: string,
descriptor: PropertyDescriptor,
) {
console.log('方法装饰器1:', targetPrototype, methodName, descriptor);
}
let methodDecorator2: any = function (params: string) {
console.log('方法装饰器2 before:', params);
return function (
targetPrototype: any,
methodName: string,
descriptor: PropertyDescriptor,
) {
console.log('方法装饰器2:', targetPrototype, methodName, descriptor);
};
};
let methodDecorator3: any = function (params: string) {
console.log('方法装饰器3 before:', params);
return function (
targetPrototype: any,
methodName: string,
descriptor: PropertyDescriptor,
) {
console.log('方法装饰器3:', targetPrototype, methodName, descriptor);
let originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
args = args.map((item) => (item += ' test'));
return originalMethod.apply(this, args);
};
return descriptor;
};
};
/**
* 方法参数装饰器
* @param targetPrototype 构造函数的原型
* @param methodName 方法名称
* @param paramIndex 参数在arguments中的下标
*/
function paramDecorator1(
targetPrototype: any,
methodName: string,
paramIndex: number,
) {
console.log('方法参数装饰器1:', targetPrototype, methodName, paramIndex);
}
function paramDecorator2(params: string) {
console.log('方法参数装饰器2 before:', params);
return function (
targetPrototype: any,
methodName: string,
paramIndex: number,
) {
console.log('方法参数装饰器2:', targetPrototype, methodName, paramIndex);
};
}
function paramDecorator3(params: string) {
console.log('方法参数装饰器3 before:', params);
return function (
targetPrototype: any,
methodName: string,
paramIndex: number,
) {
console.log('方法参数装饰器3:', targetPrototype, methodName, paramIndex);
};
}
/**
* 静态属性修饰器
* @param targetPrototype
* @param propName
*/
function staticPropDecorator(param: string) {
console.log('静态属性修饰器 before:', param);
return function (targetPrototype: any, propName: string) {
console.log(
'静态属性修饰器:',
targetPrototype,
propName,
targetPrototype[propName],
);
targetPrototype[propName] = '静态属性初始值被修改了!';
};
}
/**
* 静态方法修饰器
* @param targetPrototype
* @param methodName
* @param descriptor
*/
function staticMethodDecorator(param: string) {
console.log('静态方法修饰器 before:', param);
return function (
targetPrototype: any,
methodName: string,
descriptor: PropertyDescriptor,
) {
console.log('静态方法修饰器:', targetPrototype, methodName, descriptor);
};
}
/**
* 类装饰器
* @param targetClass
*/
function classDecorator1(constructor: Function) {
console.log('类装饰器1:', constructor);
}
function classDecorator2(params: string) {
console.log('类装饰器2 before:', params);
return function (constructor: Function) {
console.log('类装饰器2:', constructor);
};
}
function classDecorator3(params: string) {
console.log('类装饰器3 before:', params);
return function (constructor: Function) {
console.log('类装饰器3:', constructor);
};
}
@classDecorator1
@classDecorator2('params2')
@classDecorator3('params3')
class Test {
@propDecorator1
@propDecorator2('param2')
@propDecorator3('param3')
public msg: string = '属性初始值';
@staticPropDecorator('静态属性')
static title: string = '静态属性初始值';
constructor(msg: string) {
this.msg = msg;
}
@methodDecorator1
@methodDecorator2('param2')
@methodDecorator3('param3')
toString(
@paramDecorator1 str1: string,
@paramDecorator2('param2') str2: string,
@paramDecorator3('param3') str3: string,
) {
console.log('toString:', str1, str2, str3);
}
@staticMethodDecorator('静态方法')
static staticToString() {
console.log(this.title);
}
}
let t: any = new Test('this is a msg.');
t.toString('ss', 'dd', 'ff'); //methodDecorator3装饰器对该方法进行了重写
console.log(t.msg, t.__proto__.msg);
Test.staticToString();
运行结果:
ts
/* 属性装饰器2 before: param2
属性装饰器3 before: param3
属性装饰器3: Test { toString: [Function] } msg
属性装饰器2: Test { toString: [Function] } msg undefined
属性装饰器1: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } msg
方法装饰器2 before: param2
方法装饰器3 before: param3
方法参数装饰器2 before: param2
方法参数装饰器3 before: param3
方法参数装饰器3: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } toString 2
方法参数装饰器2: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } toString 1
方法参数装饰器1: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } toString 0
方法装饰器3: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } toString { value: [Function],
writable: true,
enumerable: true,
configurable: true }
方法装饰器2: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } toString { value: [Function],
writable: true,
enumerable: true,
configurable: true }
方法装饰器1: Test { toString: [Function], msg: '会在原型上面添加该属性并赋值,不是实例对象' } toString { value: [Function],
writable: true,
enumerable: true,
configurable: true }
静态属性修饰器 before: 静态属性
静态属性修饰器: function Test(msg) {
this.msg = "属性初始值";
this.msg = msg;
} title 静态属性初始值
静态方法修饰器 before: 静态方法
静态方法修饰器: function Test(msg) {
this.msg = "属性初始值";
this.msg = msg;
} staticToString { value: [Function],
writable: true,
enumerable: true,
configurable: true }
类装饰器2 before: params2
类装饰器3 before: params3
类装饰器3: function Test(msg) {
this.msg = "属性初始值";
this.msg = msg;
}
类装饰器2: function Test(msg) {
this.msg = "属性初始值";
this.msg = msg;
}
类装饰器1: function Test(msg) {
this.msg = "属性初始值";
this.msg = msg;
}
toString: ss test dd test ff test
this is a msg. 会在原型上面添加该属性并赋值,不是实例对象
静态属性初始值被修改了! */