TypeScript 装饰器入门核心用法

一、什么是装饰器?

装饰器就是普通函数 ,用 @装饰器名 贴在类、方法、属性上,作用就是给被装饰的东西加额外功能,仅此而已。

二、最基础用法:类装饰器

直接贴在类上,函数唯一参数是被装饰类的构造函数,最简单的例子:给类加静态属性。

typescript 复制代码
// 定义装饰器函数:给类加版本号
function addVersion(target) {
  target.version = '1.0.0'; // 给类挂载静态属性
}

// 用@贴在类上,完成装饰
@addVersion
class MyClass {}

// 直接使用装饰器加的属性
console.log(MyClass.version); // 输出:1.0.0

核心逻辑:@addVersion 等价于 addVersion(MyClass),把类传给装饰器函数就行。

三、最常用用法:方法装饰器

贴在类的方法上,日常用得最多,函数有 3 个固定参数:不用死记含义,跟着案例用就会。

简单案例1:给方法加日志

执行方法时,自动打印"方法被调用了",不用在方法里写重复代码。

typescript 复制代码
// 方法装饰器:打印方法调用日志
function showLog(target, name, descriptor) {
  // 保存原方法
  const oldFn = descriptor.value;
  // 重写方法,加日志逻辑
  descriptor.value = function() {
    console.log(`【日志】${name}方法被调用了`);
    oldFn.apply(this); // 执行原来的方法
  };
}

class MyClass {
  // 装饰器贴在方法上
  @showLog
  sayHi() {
    console.log('hello TS');
  }
}

new MyClass().sayHi();
// 输出:【日志】sayHi方法被调用了 → hello TS

简单案例2:禁止方法被修改

让方法只读,不能被重新赋值,避免误改方法逻辑。

typescript 复制代码
// 方法装饰器:禁止方法修改
function noChange(target, name, descriptor) {
  descriptor.writable = false; // 设为不可写
}

class MyClass {
  @noChange
  fn() {
    console.log('不能改我');
  }
}

const obj = new MyClass();
obj.fn = () => {}; // 报错:无法分配到 "fn",因为它是只读属性

四、属性装饰器:给属性加默认值

贴在类的属性上,函数有 2 个参数,最简单的用法:给属性设置默认值,不用在构造函数里初始化。

typescript 复制代码
// 属性装饰器:设置默认值
function setDefault(val) {
  return function(target, name) {
    target[name] = val;
  };
}

class MyClass {
  // 贴在属性上,传默认值
  @setDefault('张三')
  name;

  @setDefault(20)
  age;
}

console.log(new MyClass().name); // 输出:张三
console.log(new MyClass().age); // 输出:20

五、装饰器工厂:给装饰器传参

想给装饰器传自定义参数(比如日志加前缀、默认值自定义),就写装饰器工厂------本质是「返回装饰器的函数」,写法超简单,看案例就会。

案例:带前缀的日志装饰器

让日志有自定义前缀,不用写多个装饰器函数。

typescript 复制代码
// 装饰器工厂:接收自定义前缀
function log(prefix) {
  // 返回真正的装饰器函数
  return function(target, name, descriptor) {
    const oldFn = descriptor.value;
    descriptor.value = function() {
      console.log(`【${prefix}】${name}方法执行了`);
      oldFn.apply(this);
    };
  };
}

class MyClass {
  // 传参使用:自定义前缀"接口请求"
  @log('接口请求')
  getData() {}

  // 传参使用:自定义前缀"操作"
  @log('操作')
  saveData() {}
}

new MyClass().getData(); // 输出:【接口请求】getData方法执行了
new MyClass().saveData(); // 输出:【操作】saveData方法执行了

六、必记规则:多个装饰器的执行顺序

一个类/方法上贴多个装饰器时,从下往上执行------谁离被装饰的东西近,谁先执行。

typescript 复制代码
// 定义两个简单装饰器
function A(target) {
  console.log('执行装饰器A');
  return target;
}
function B(target) {
  console.log('执行装饰器B');
  return target;
}

// B离类更近,先执行;A后执行
@A
@B
class MyClass {}

// 运行结果:先打印「执行装饰器B」,再打印「执行装饰器A」

等价理解:MyClass = A(B(MyClass)),先执行内层的 B,再执行外层的 A。

七、使用前提:开启TS配置

装饰器是 TS 实验性特性,必须在 tsconfig.json 里加一行配置,否则报错,就加这一个核心项就行:

json 复制代码
{
  "compilerOptions": {
    "experimentalDecorators": true, // 必须开启,启用装饰器
    "target": "ES5" // 项目基本配置,一般都有
  }
}
相关推荐
GreenTea1 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd3 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌3 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈3 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫4 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝4 小时前
svg图片
前端·css·学习·html·css3
橘子编程4 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇4 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧4 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint
大家的林语冰5 小时前
《前端周刊》尤大开源 Vite+ 全家桶,前端工业革命启动;尤大爆料 Void 云服务新产品,Vite 进军全栈开发;ECMA 源码映射规范......
前端·javascript·vue.js