@表达式 形式贴在类、方法、属性、参数上,编译时执行并"修改"目"> @表达式 形式贴在类、方法、属性、参数上,编译时执行并"修改"目"> @表达式 形式贴在类、方法、属性、参数上,编译时执行并"修改"目">
TypeScript 词条目录
前端Wiki/TypeScript/深入/装饰器与元数据

装饰器基础

装饰器(decorator)是一种特殊声明:以 @表达式 形式贴在类、方法、属性、参数上,编译时执行并"修改"目标。常见于 NestJS 后端框架与 TypeORM 等库,是注解式编程的基础。

方法装饰器收到三个参数:(原型、方法名、属性描述符)。记录耗时、拦截调用、改权限这类横切需求,用装饰器写一次贴到处,比在每个方法里塞代码干净得多。装饰器目前仍是实验性特性,需在 tsconfig 开启。

  • 类装饰器:在 class 声明上方,参数是构造函数
  • 方法装饰器:三个参数(原型、方法名、描述符),常用来包装方法
  • 实验性特性,需在 tsconfig 开启 experimentalDecorators
TS
// 方法装饰器:记录函数耗时
function logTime(target: any, key: string, desc: PropertyDescriptor) {
  const fn = desc.value;
  desc.value = function (...args: any[]) {
    const t0 = Date.now();
    const result = fn.apply(this, args);
    console.log(key + ' 耗时:', Date.now() - t0, 'ms');
    return result;
  };
}

class Service {
  @logTime
  heavyWork(n: number) {
    let sum = 0;
    for (let i = 0; i < n; i++) sum += i;
    return sum;
  }
}
new Service().heavyWork(100000);
JS
// 装饰器编译成普通函数调用
function logTime(target, key, desc) {
  var fn = desc.value;
  desc.value = function () {
    var args = [];
    for (var _i = 0; _i < arguments.length; _i++) args[_i] = arguments[_i];
    var t0 = Date.now();
    var result = fn.apply(this, args);
    console.log(key + ' 耗时:', Date.now() - t0, 'ms');
    return result;
  };
}
var Service = /** @class */ (function () {
  function Service() {}
  Service.prototype.heavyWork = function (n) {
    var sum = 0;
    for (var i = 0; i < n; i++) sum += i;
    return sum;
  };
  __decorate([logTime], Service.prototype, 'heavyWork');
  return Service;
})();
console.log(new Service().heavyWork(100000));
本节要点装饰器是贴在类成员上的编译期注解,横切逻辑(日志/耗时/拦截)写一次贴到处。