TS-装饰器篇 | 01

TS-装饰器篇 | 01

基本介绍

装饰器是一种特殊类型的声明,它能够被附加到方法属性或者参数上,

  • 语法:装饰器使用 @expression 这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入
  • 若要启用实验性的装饰器特性,必须tsconfig.json里启用experimentalDecorators编译器选项
  • 常见的装饰器有: 类装饰器属性装饰器方法装饰器参数装饰器
  • 装饰器的写法: 分为普通装饰器(无法传参)装饰器工厂(可以传参)

装饰器的语法十分简单,只需要在想使用的装饰器前加上@符号,装饰器就会被应用到目标上:

function simpleDecorator() {
  console.log('---hi I am a decorator---')
}

@simpleDecorator
class A {}
普通装饰器
// 加上通过类型提示
interface Person {
  name: string
  address: string
}

function enhancer(target: any) {
  console.log('class enhancer')
  target.prototype.name = 'TS 装饰器'
  target.prototype.address = 'ECMAScript 2022'
}

@enhancer // 普通装饰器
class Person {
  constructor() {}
}

const person = new Person()
console.log(person.name)
console.log(person.address)

// class enhancer
// TS 装饰器
// ECMAScript 20222

装饰器工厂

可以通过传递参数的方式注入需要的数据

// options 传递过来的对象都可以注入到Class的原型上
function Component(options: { id: number; address: string }) {
  return function (target: any) {
    target.prototype.id = options.id
  }
}

@Component({
  id: 1,
  address: '2',
})
class Cat {
  id: number | undefined

  constructor() {}

  printId(prefix: string) {
    console.log(prefix + this.id)
  }
}

const cat = new Cat()
cat.printId('MortenID: ')
// MortenID: 1

装饰器分类

装饰器分类
装饰器分类
// 类装饰器
@classDecorator
class Bird {

  // 属性装饰器
  @propertyDecorator
  name: string;
  
  // 方法装饰器
  @methodDecorator
  fly(
    // 参数装饰器
    @parameterDecorator
      meters: number
  ) {}
  
  // 访问器装饰器
  @accessorDecorator
  get egg() {}
}

类装饰器

类装饰器在类声明之前声明(紧靠着类声明),用来监视修改或者替换类定义

// 加上通过类型提示
interface Person {
  name: string
  address: string
}

function enhancer(target: any) {
  console.log('class enhancer')
  target.prototype.name = 'TS 装饰器'
  target.prototype.address = 'ECMAScript 2022'
}

@enhancer // 普通装饰器
class Person {
  constructor() {}
}

const person = new Person()
console.log(person.name)
console.log(person.address)

属性装饰器

属性装饰器表达式会在运行时当做函数被调用,传入下列两个参数

  • 第一个参数: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 第二个参数: 是属性的名称
function propertyDecorator(target: any, propertyKey: string) {
  console.log(target, propertyKey)
}

class Car {
  @propertyDecorator
  carName: string

  constructor() {
    this.carName = 'BBA'
  }
}

const car = new Car()
console.log(car.carName)
// {} carName
// BBA

我们再修改一下实例成员为静态成员

class Car {
  @propertyDecorator
  // add static
  static carName: string

  constructor() {
    this.carName = 'BBA'
  }
}
// 输出类的构造函数
// [class Car] carName

方法装饰器

方法装饰器用来装饰方法

  • 第一个参数: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 第二个参数: 是方法的名称
  • 第三个参数: 是方法的描述修饰方法
function methodDecorator(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor,
) {
  console.log(target, propertyKey, descriptor)
    // {} test {
 //   value: [Function: test],
 //   writable: true,
 //     enumerable: false,
 //     configurable: true
 // }
  const method = descriptor.value // 获取原来方法
  console.log(method.toString()) //test(){return"test"}  结果正好和定义的函数表达式相同
  descriptor.value = () => {
    // 调用原来的方法结果再加上一些其他操作
    return `<div>${method()}</div>`
  }
}

class Config {
  @methodDecorator
  test() {
    return 'test'
  }
}
const c = new Config()

console.log(c.test())
// <div>test</div>

参数装饰器

参数装饰器用来装饰参数

  • 第一个参数: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 第二个参数: 成员的名字
  • 第三个参数: 参数在函数参数列表中的索引
function parameterDecorator(
  target: any,
  propertyKey: string,
  parameterIndex: number,
) {
  console.log(target, propertyKey, parameterIndex)  // {} getPrice 0
}

class Vehicle {
  price = '1000$'
  color: string | undefined

  constructor(color: string) {
    this.color = ' ' + color
  }

  getPrice(@parameterDecorator prefix: string): string {
    return prefix + this.price + this.color
  }
}

const v = new Vehicle('red')
console.log(v.getPrice('Q4: '))  // Q4: 1000$ red

装饰器执行顺序

执行顺序 属性>方法>方法参数>类 注:如果有多个同样的装饰器,它会先执行后面的装饰器。

  • 属性装饰器最先执行,谁先写先执行谁
  • 参数装饰器再执行,
  • 方法装饰器再执行
  • 类装饰器最后执行
  • 如果同类型,先执行离类近的
  • 属性/方法/访问器装饰器而言,执行顺序取决于声明它们的顺序,两个同样的方法先声明先执行。
function classDecorator(target: any) {
  console.log('classDecorator begin')
}

function propertyDecorator(target: any, propertyKey: string) {
  console.log('propertyDecorator begin')
}

function parameterDecorator(
  target: any,
  propertyKey: string,
  parameterIndex: number,
) {
  console.log('parameterDecorator begin')
}

function methodDecorator(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor,
) {
  console.log('methodDecorator begin')
}

@classDecorator
class OrderDecorator {
  @propertyDecorator
  order: number[] = [1, 3, 4, 5, 6]

  constructor() {}

  getOrder(@parameterDecorator id: number): number {
    return this.order[id]
  }

  @methodDecorator
  test() {
    return 'test'
  }
}

const order = new OrderDecorator()
console.log(order.getOrder(2))
// propertyDecorator begin
// parameterDecorator begin
// methodDecorator begin
// classDecorator begin
// 4


如果同类型,先执行离类近的

// 如果同类型,先执行离类近的
function first() {
  console.log('first(): factory evaluated')
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor,
  ) {
    console.log('first(): called')
  }
}

function second() {
  console.log('second(): factory evaluated')
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor,
  ) {
    console.log('second(): called')
  }
}

class ExampleClass {
  @first()
  @second()
  method() {}
}
// first(): factory evaluated
// second(): factory evaluated
// second(): called
// first(): called

装饰器的执行时机

装饰器只在解释执行时应用一次,所有装饰器的执行在编译时而不是运行时

function f(C) {
  console.log('apply decorator')
  return C
}

@f
class A {}

// output: apply decorator

参考

TypeScript装饰器完全指南

How TypeScript Decorators really work | TypeScript in a Nutshell

本文由 mdnice 多平台发布

装修网简装每平方米大约多少钱100平米米装修公装的装修公司网吧装修一般要多少钱精装会议小厨宝装卫生间一般装到哪里公装一般多少钱一平方西安简装多少钱40平装修大概多少钱成都装修100平的房子要多少钱出租屋简装家装饰装修卧室简装住宅卫生间装修精装房装修多少钱顶复装修浦东三室一厅装修160平简装多少钱成都装修公司口碑排行金融装饰住宅装饰设计简装流程武汉三室一厅装修价格酒店装修每平方大约要多少钱110平方全包装修要多少钱建筑装饰公装简装装修公司室内景观装饰家庭简装效果图厨房厕所装修需要多少钱香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声汪小菲曝离婚始末卫健委通报少年有偿捐血浆16次猝死单亲妈妈陷入热恋 14岁儿子报警雅江山火三名扑火人员牺牲系谣言手机成瘾是影响睡眠质量重要因素男子被猫抓伤后确诊“猫抓病”中国拥有亿元资产的家庭达13.3万户高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了男孩8年未见母亲被告知被遗忘张家界的山上“长”满了韩国人?倪萍分享减重40斤方法许家印被限制高消费网友洛杉矶偶遇贾玲何赛飞追着代拍打小米汽车超级工厂正式揭幕男子被流浪猫绊倒 投喂者赔24万沉迷短剧的人就像掉进了杀猪盘特朗普无法缴纳4.54亿美元罚金周杰伦一审败诉网易杨倩无缘巴黎奥运专访95后高颜值猪保姆德国打算提及普京时仅用姓名西双版纳热带植物园回应蜉蝣大爆发七年后宇文玥被薅头发捞上岸房客欠租失踪 房东直发愁“重生之我在北大当嫡校长”校方回应护栏损坏小学生课间坠楼当地回应沈阳致3死车祸车主疑毒驾事业单位女子向同事水杯投不明物质路边卖淀粉肠阿姨主动出示声明书黑马情侣提车了奥巴马现身唐宁街 黑色着装引猜测老人退休金被冒领16年 金额超20万张立群任西安交通大学校长王树国卸任西安交大校长 师生送别西藏招商引资投资者子女可当地高考胖东来员工每周单休无小长假兔狲“狲大娘”因病死亡外国人感慨凌晨的中国很安全恒大被罚41.75亿到底怎么缴考生莫言也上北大硕士复试名单了专家建议不必谈骨泥色变“开封王婆”爆火:促成四五十对测试车高速逃费 小米:已补缴天水麻辣烫把捣辣椒大爷累坏了

装修网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化