Skip to content

12-装饰器

装饰器对前端的意义

装饰器是前端了不起的技术革命,弥补了只有后端语言才有 AOP[类似装饰器]的短板,学习装饰器好处有:

  • 1.较大提升前端架构思维和前端架构能力,装饰器底层蕴含的拦截器思想在Java Spring,Nestjs框架,python 各种后端语言中都有广泛的应用,而拦截器展示的就是一种架构思维,通过学习装饰器能扩大技术视野,是作为一名前端架构师以及晋级更高职位必会技能
  • 2.Nestis 等相对新型的 非常优秀的 Nodejs 框架大量运用了 TS 装饰器,例如: @Controller @Service@Get @Post
  • 3.在面试中,如果告诉面试官,你精通装饰器,这也能成为你的大加分项,因为公司更需架构思维能力强的前端工程师,因为具有架构思维的前端开发人员在大中项目中一定能写出扩展性更好的代码。

装饰器应用

装饰器概述

1.装饰器的定义

装饰器就是一个方法或者叫函数,可以注入【写到】到类、方法、属性、参数,对象上,扩展其功能。

2.装饰器要解决的问题

装饰器就就是解决在不修改原来类、方法,属性,参数的时候为其添加额外的功能。

比如:为整个项目的所有业务类【假如50个类】的所有方法【假如6个方法】都增加日志信息,如果一个一个的增加,那要增加300次日志调用语句,假如日后日志文件格式发生了改变,也还需要修改300次。 如果有了装饰器,只需要修改一次就可以。这个属于项目中的通用功能,大家了解下即可,后面仿 Nestis 实战 时对装饰器的这个特性会有很深的体会。

在 Nestis 中 装饰器可以解决依赖注入的问题,而依赖注入是 Java等后端语言拥有的非常优秀的编程思想有了依赖注入,能大大降低项目的耦合度,大大提升项目的可扩展性。

3.装饰器分类

常见的装饰器:类装饰器、属性装饰器、方法装饰器、参数装饰器,元数据装饰器。

4.元数据装饰器初步理解

元数据装饰器:在定义类或者类方法的时候,可以设置一些元数据,我们可以获取到在类与类方法上添加的元数据,需要引入 reflect-metadata 第三方库 采用 @Reflect.metadata来实现。

元数据指的是描述东西时用的数据,例如: Reflect.metadata("importinfo","疫情期间用公筷戴口罩”)

5.装饰器两种写法

写法1:让调用时(使用时) 不传递参数的装饰器

写法2:装饰器工厂【让调用时 可以传递参数的装饰器】

typescript写装饰器前的项目配置

1.安装 concurrently 支持合并执行,同时运行多个 script 命令库

bash
pnpm add concurrently -S

2.tsconfig.json 文件修改如下:

json
--编译输入输出目录
"outDir":"./dist"
"rootDir":"./src'

-- 消除装饰器警告(支持编写装饰器)
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

3.配置 package.json 文件脚本信息

json
"scripts": {
	"dev:build": "tsc -w",
    
    --监控 dist/teaching 目录中的 js 文件,变化时执行 node 命令
    "dev:start": "nodemon --watch dist/teaching js --exec node/dist/teaching/1cTassDecorator.js",
    
    --合并启动
    "start": "concurrently npm:dev:*",
    
    --命令解决 typescript 编译装饰器类时出现的 bug
    "tsc": "tsc src/teaching/1ClassDecorator.ts --target ES5 -w --experimentalDecorators",
    
    --本章后面章节会用到,先配置上
    "ctr1": "ts-node src/contro1ler/HomeContro1ler.ts",
    "beginapp": "nodemon --watch src/ -e ts --exec ts-node./src/expressapp.ts",
    
}

类装饰器的两种实现[带参数和不带参数]

不带参数的类装饰器

typescript
// 定义一个不带参数的类装饰器
function sealed(target: Function) {
  // 对类的构造函数和原型进行密封
  Object.seal(target);
  Object.seal(target.prototype);
}

// 使用类装饰器
@sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return "Hello, " + this.greeting;
  }
}

带参数的类装饰器

typescript
// 定义一个带参数的类装饰器
function color(value: string) {
  // 返回一个装饰器函数
  return function (target: Function) {
    // 在类的原型上添加一个属性
    target.prototype.color = value;
  };
}

// 使用类装饰器
@color("red")
class Car {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  run() {
    return this.name + " is running with " + this.color + " color.";
  }
}

装饰器底层 JS 源码

装饰器实战

Released under the MIT License.