装饰器是一种特殊类型的声明,它能被附加到类声明,方法,属性或者参数上,可以修改类的行为。
装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
常见的装饰器有:
- 类装饰器
- 属性装饰器
- 方法装饰器
- 参数装饰器
1 类装饰器
function log(target: any) {target.prototype.log = function () {console.log(11111111)}return target}@logclass User { }const user = new User()user.log();
2 属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列两个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 成员的名字
function setDefaultProp(val: string) {return function (target: any, name: any) {target[name] = val;}}class Chinese {// 静态属性,target => 类的构造函数@setDefaultProp('Chinese people are from china.')public static region: string = 'china';// 实例属性,target => 类的原型对象@setDefaultProp('原型链上的name')public id!: string;}const user = new Chinese()console.log(user)

3 方法装饰器
方法装饰器被应用到方法的属性描述符上,可以用来监视、修改、替换方法的定义。
方法装饰器会在运行时传入3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象;
- 成员的名字
- 成员的属性描述符;
// 记录函数耗时function takeUpTime(target: any, name: string, descriptor: any) {const func = descriptor.value;descriptor.value = function () {const start = new Date().getTime()func.apply(this, arguments);const end = new Date().getTime()console.log(name, '--- 总共耗时', end - start, 'ms')}}class User {// 静态方法, target => 类的构造函数@takeUpTimestatic run() {console.log('我在跑步')for (let i = 0; i < 1000; i++) {console.log('跑步...')}console.log('跑步完了')}// 实例方法, target => 类的原型对象@takeUpTimestudy() {console.log('我在学习')for (let i = 0; i < 1000; i++) {console.log('学习...')}console.log('学习完了')}}User.run();const user = new User()user.study()
4 参数装饰器
参数装饰器表达式会在运行时被调用,可以为类的原型增加一些元素数据,传入3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
- 方法名称
- 参数在函数参数列表中的索引
function logParams(params: any) {console.log(params)return function (target: any, methodName: any, paramIndex: any) {console.log(target)console.log(methodName)console.log(paramIndex)console.log('---------')}}class User {// 实例方法, target => 类的原型对象study(@logParams('course') course: string,) { }// 静态方法, target => 类的构造函数static run(@logParams('where') where: string,) { }}
5 装饰器的执行顺序
当有多个装饰器装饰同一个内容时,
- 装饰顺序,从里到外
- 执行顺序,从外到内
不同类型的装饰器:
- 装饰顺序:属性装饰器 > 方法装饰器 > 参数装饰器 > 类装饰器
