什么是装饰器?如何使用?

今天咱们聊聊装饰器,这玩意儿在TypeScript和现代前端框架里出场率越来越高,但总让人觉得有点“魔法”色彩。别把它想得太玄乎,其实它就是一种特殊的语法,让你能优雅地给类、方法或者属性“加点料”。

你可以把装饰器想象成一个高级的包装纸。你想送个礼物(比如一个类或者一个函数),但觉得光秃秃的不够好看,就用包装纸(装饰器)给它包一层,加点丝带啊、卡片啊(也就是额外的功能)。最关键的是,你不用拆开礼物本身去修改它。

看看它长什么样。一个最简单的装饰器就是一个函数,它会在运行时被调用,接收到的参数就是它要装饰的那个目标。比如给类用的装饰器:

function LogClass(constructor: Function) {
  console.log(`装饰的类是: ${constructor.name}`);
}

@LogClass
class MyService {
  // ...
}

当你运行这段代码,控制台就会立刻打出装饰的类是: MyService。这个@LogClass就是装饰器语法,它直接作用在MyService这个类上。LogClass函数在类被定义的时候就执行了,constructor参数就是类的构造函数。

方法装饰器更常用,也更有意思。它能让你在方法执行前后“插一脚”。

function LogMethod(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args: any[]) {
    console.log(`调用方法: ${key}, 参数:`, args);
    const result = originalMethod.apply(this, args);
    console.log(`方法 ${key} 执行完毕`);
    return result;
  };
  return descriptor;
}

class Calculator {
  @LogMethod
  add(x: number, y: number) {
    return x + y;
  }
}

这时候你调用calculator.add(1, 2),控制台会先打印出调用信息和参数,执行完原方法后再打印一条完成信息。看到了吗?我们不动add方法内部一行代码,就给它加上了完整的日志功能。这就是装饰器的威力——面向切面编程。像日志、性能监控、权限校验这种横跨多个方法的通用逻辑,用装饰器来封装是再合适不过了。

除了类和方法,属性、访问器(getter/setter)甚至参数也都能被装饰。不过得提醒你,要玩转装饰器,你得先在tsconfig.json里把experimentalDecorators这个选项设为true,因为这在ECMAScript里还是个提案,不算最终标准。

用的时候也悠着点。装饰器堆叠太多,代码的执行顺序会变得难以跟踪,调试起来有点头疼。我的建议是,把装饰器用在那些真正通用的、非业务核心的横切关注点上。如果你发现某个装饰器里的逻辑跟某个具体业务绑得特别死,那可能就该考虑换种实现方式了。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容