Skip to content

ts
// 装饰器就是一个方法,可以注入到类、方法、属性上来扩展类、属性、方法、参数的功能
// 写法:1.普通装饰器(无法传参) 2.装饰器工厂(可传参)

// 1. 类装饰器
// 类装饰器在类之前被声明(紧靠类声明)。类装饰器应用于类构造函数、可以用来监视、修改或替换类定义
// 普通装饰器
function logClass(params: any) {
  console.log(params)
  // 通过原型链拓展类、属性、方法、参数
  params.prototype.apiUrl = 'xxx'
  params.prototype.run = function () {
    console.log('run.......')
  }
}

@logClass
class HttpClient {
  constructor() { }
  getData() { }
}

// http对象扩展了run方法
const http = new HttpClient()
console.log(http)
http.run()

// 装饰器工厂(可传参)
function logClass1(params: string) {
  return function (target: any) {
    console.log(params)
    console.log(target)
    target.prototype.apiUrl = params
  }
}

// 通过装饰器工厂,装饰器可以传递参数
@logClass1('hello')
class HttpClient1 {
  constructor() { }
  getData() { }
}

const http1 = new HttpClient1()
console.log(http1)

// 重载构造函数
function logClass2(target: any) {
  return class extends target {
    api = 'api22222'
    getData() {
      console.log(`${this.api}3333`)
    }
  }
}

@logClass2
class HttpClient2 {
  public api: string | undefined
  constructor() {
    this.api = 'api11111'
  }

  getData() {
    console.log(this.api)
  }
}

const http2: any = new HttpClient2()
console.log(http2)
http2.getData
ts
// 2.方法装饰器
// 应用在方法的属性描述上,可以用来监视、修改、替换方法定义
// 接收三个参数
// 1. 对于静态成员是类的构造函数,对于实例成员是类的原型对象
// 2. 成员的名字
// 3. 成员的属性的描述
function logClass4(params: string) {
  return function (target: any, methodsName: any, desc: any) {
    console.log('类的原型对象', target)
    console.log('成员的名字', methodsName) // getData
    console.log('成员的属性的描述', desc) // {writable: true, enumerable: true, configurable: true, value: ƒ}
    console.log(desc.value) // f() {.....}
    const o = desc.value
    desc.value = function (...args: any[]) {
      args = args.map((item) => {
        return String(item) + params
      })
      o.apply(this, args)
    }
  }
}

class HttpClient4 {
  public api: any | undefined
  public name = 'name'
  constructor(name: string) { }
  @logClass4('方法装饰器')
  getData(...args: any[]) {
    console.log('参数', args) // ["123方法装饰器","xxx方法装饰器"]
    console.log('方法执行完毕: getData')
  }
}

const http4 = new HttpClient4('test')
http4.getData(123, 'xxx')
ts
// 3. 属性装饰器
// 属性装饰器表达式会在运行时被当做函数调用
// 接收两个参数
// 1.对于静态成员是类的构造函数,对于实例成员是类的原型对象
// 2.成员的名字

// 属性装饰器
function logProperty(params: string) {
  return function (target: any, attr: any) {
    target[attr] = params
  }
}

class HttpClient3 {
  @logProperty('hello')
  public api: any | undefined

  constructor() { }
  getData() { }
}
const http3: any = new HttpClient3()
console.log(http3)
ts
// 4.参数装饰器
// 参数装饰器表达式会在运行时当做函数被调用,可以使参数装饰器为类的原型增加一些元素数据
// 1.对于静态成员是类的构造函数,对于实例成员是类的原型对象
// 2.参数的名字
// 3.参数索引
function logClass5(params: string) {
  return function (target: any, methodsName: any, desc: any) {
    console.log(target)
    console.log(methodsName)
    console.log(desc)
  }
}

class HttpClient5 {
  public api: any | undefined
  constructor() { }

  getData(@logClass5('参数装饰器') uuid: any) {
    console.log(uuid)
  }
}

const htt5: any = new HttpClient5()
htt5.getData(122)
ts
// 5.访问器装饰器

function configurable(value: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.configurable = value
  }
}

class Point {
  private _x: number
  private _y: number
  constructor(x: number, y: number) {
    this._x = x
    this._y = y
  }

  @configurable(false)
  get x() {
    return this._x
  }

  @configurable(false)
  get y() {
    return this._y
  }

}