装饰器是一种特殊类型的声明,它能够附加到类、类的函数、类属性、类函数的参数上,以达到修改类的行为
一、装饰器的种类
-
1、根据装饰器的位置
- 类装饰器
- 类函数装饰器
- 类属性装饰器
- 类函数参数装饰器
-
2、根据装饰器是否有参数
- 无参装饰器(一般装饰器)
- 有参装饰器(装饰器工厂)
二、类的装饰器
-
1、类装饰器的写法
function desc(target) { console.log('---------------类的装饰器参数 start------------------'); console.log(target); // 输出 [Function: Person]表示当前装饰的类 console.log('---------------类的装饰器参数 end------------------'); } @desc // 使用装饰器 class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } } let p = new Person('哈哈', 20); -
2、使用类的装饰器扩展类的属性和方法
function desc(target) { console.log('---------------类的装饰器参数 start------------------'); console.log(target); console.log('---------------类的装饰器参数 end------------------'); return class extends target{ // 在react高阶组件中经常看到这种写法 gender = '男'; say() { console.log(this.name, this.age, this.gender); } } } @desc class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } } let p = new Person('哈哈', 20); console.log(p); p.say(); /* ---------------类的装饰器参数 start------------------ [Function: Person] ---------------类的装饰器参数 end------------------ class_1 { name: '哈哈', age: 20, gender: '男' } 哈哈 20 男 */ -
3、使用装饰器修改类的构造函数(构造函数的重载、方法重载)
function desc(target) { return class extends target{ name = '我是重载后的'; sayHell() { console.log('我是重载后的', this.name); } } } @desc class Person { public name: string | undefined; public age: number | 0; constructor() { this.name = '哈哈'; this.age = 20; } sayHell() { console.log('hello word', this.name); } } let p = new Person(); console.log(p); p.sayHell(); -
4、装饰器工厂的写法
function desc(params: string) { return function (targe: any) { console.log('---------------参数说明 start------------------'); console.log('params', params); console.log('target', targe); console.log('---------------参数说明 end------------------'); // 直接在原型上扩展一个属性 targe.prototype.apiUrl = params; } } @desc('http://www.baidu.com') class P { say() { console.log('说话') } } let p:any = new P(); console.log(p.apiUrl);
三、类函数装饰器
它应用到方法上,可以用来监视、修改、替换该方法
-
1、定义方式
function desc(target, key, descriptor) { console.log('---------------类的装饰器参数 start------------------'); console.log('target', target); // Person { say: [Function] } 表示类的原型 console.log('key', key); // 被装饰的函数名 console.log('descriptor', descriptor); // 被装饰的函数的对象属性 console.log('---------------类的装饰器参数 end------------------'); } -
2、使用
class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } @desc say() { console.log('说的方法') } } -
3、在装饰器中添加类的原型属性和原型方法
function desc(target, key, descriptor) { target.gender = '男'; target.foo = function () { console.log('我是原型上的方法') } } // 测试代码 let p = new Person('哈哈', 20); console.log(p); console.log(Person.prototype); p.say(); console.log(p.gender); // 使用p原型链上的属性 p.foo() // 调用了p原型链上的方法 -
4、使用装饰器拦截函数的调用(替换)
function desc(params: string) { return function (target: any, key: string, descriptor: {[propsName: string]: any}) { // 修改被装饰的函数的 let method = descriptor.value; descriptor.value = function (...args: Array<any>) { args = args.map(it => String(it)); console.log(args); // method.apply(this, args); } } } class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } @desc('装饰器上的参数') say() { console.log('说的方法') } } let p = new Person('哈哈', 20); console.log(p); p.say(123, 23, '你好'); -
5、使用装饰器拦截函数的调用(附加新的功能)
function desc(params: string) { return function (target: any, key: string, descriptor: {[propsName: string]: any}) { // 修改被装饰的函数的 let method = descriptor.value; descriptor.value = function (...args: Array<any>) { args = args.map(it => String(it)); console.log(args); method.apply(this, args); } } } class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } @desc('装饰器上的参数') say(...args) { console.log('说的方法', args) } } let p = new Person('哈哈', 20); console.log(p); p.say(123, 23, '你好');
四、类属性装饰器
-
1、定义方式
function desc(target, name) { console.log('---------------类属性装饰器的参数 start------------------'); console.log('target', target, target.constructor); // 表示类的原型 console.log('name', name); // 表示被装饰属性名 console.log('---------------类属性装饰器的参数 end------------------'); } class Person { public name: string | undefined; public age: number | 0; @desc private gender: string | undefined; constructor(name, age) { this.name = name; this.age = age; } } let p = new Person('哈哈', 20); console.log(p); -
2、在装饰器中修改属性值
function desc(target, name) { target[name] = '女'; } class Person { public name: string | undefined; public age: number | 0; @desc public gender: string | undefined; constructor(name, age) { this.name = name; this.age = age; } say() { console.log(this.name, this.age, this.gender); } } let p = new Person('哈哈', 20); console.log(p); p.say();
五、类函数参数的装饰器
参数装饰器表达式会在运行时候当做函数被调用,以使用参数装饰器为类的原型上附加一些元数据
-
1、使用方式
function desc(params: string) { return function (target: any, key, index) { console.log('---------------参数装饰器 start------------------'); console.log(target); // 类的原型 console.log(key); // 被装饰的名字 console.log(index); // 序列化 console.log('---------------参数装饰器 end------------------'); } } class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } say(@desc('参数装饰器') age: number) { console.log('说的方法') } } let p = new Person('哈哈', 20); console.log(p); p.say(20); -
2、为类的原型上添加一些东西
function desc(params: string) { return function (target: any, key, index) { console.log('---------------参数装饰器 start------------------'); console.log(target); // 类的原型 console.log(key); // 被装饰的名字 console.log(index); // 序列化 target.message = params; console.log('---------------参数装饰器 end------------------'); } } class Person { public name: string | undefined; public age: number | 0; constructor(name, age) { this.name = name; this.age = age; } say(@desc('参数装饰器') age: number) { console.log('说的方法') } } let p: any = new Person('哈哈', 20); console.log(p); p.say(20); console.log(p.message)
六、几种装饰器的执行顺序
-
1、测试代码
function logCls(params: string) { return function (target: any) { console.log('4.类的装饰器'); } } function logMehod(params: string) { return function (target: any, key: string, descriptor: {[propsName: string]: any}) { console.log('3.类的函数装饰器'); } } function logParams(params: string) { return function (target: any, name: string) { console.log('1.类属性装饰器'); } } function logQuery(params: string) { return function (target: any, key: string, index: number) { console.log('2.函数参数装饰器'); } } @logCls('类的装饰器') class Person{ @logParams('属性装饰器') public name: string | undefined; @logMehod('函数装饰器') getData(@logQuery('函数参数装饰器') age: number, @logQuery('函数参数装饰器') gender: string) { console.log('----'); } } -
2、运行结果
1.类属性装饰器 2.函数参数装饰器 3.类的函数装饰器 4.类的装饰器